矩阵乘法套线段树(动态最大子段和问题)

一个新套路,

利用矩阵能将一些复杂的线性关系转换为一次矩阵乘法。

求解只需求区间积。

采用线段树(所以需要满足结合律)

更奇特的是你可以重载矩阵乘法时内部单个元素的乘法和加法(比如说改成取max之类的)

只要重载之后仍然满足结合律

我自己想了一个判断方法。

要A*(B*C)=(A*B)*C

令A*(B*C)=D,(A*B)*C=E

有D=E

Dij=Eij

sigma(sigma(Aik*Bkl)*Clj)=sigma(Aik*sigma(Bkl*Clj))=sigma(sigma( Aik*Bkl*Clj ))

Aik*sigma(Bkl*Clj)=sigma(Aik*Bkl*Clj)

令Aik=X,Bkl*Clj=Y

X*sigma(Y)=sigma(X*Y)

然后想一想就行了。

比如让 * 为加法, + 为取max(+为sigma内的符号)

可以做动态最大子段和问题。

sum[i] 为 以i结尾的最大子段和,ans[i] 为 i之前的最大子段和, seq[i] 为 i位置上的值。

有:

seq[i]       -inf          0                        sum[i-1]                   sum[i]

seq[i]         0            0            X          ans[i-1]        =         ans[i]

0                0            0                        0                              0

 

然后ans[n]就是答案

动态修改只需要将第一个矩阵存在线段树里(有结合律可以乱搞)

单点修改,区间查询

另外矩阵乘法和线段树是两个卡常数重灾区,第一个矩阵有5个位置一直为0,不用存,乘的时候也不用像矩阵乘法一样三个for循环,挑会对答案造成影响的乘(比如第一行第二列一直都是-inf,干脆不算)。

 

给定递推式 Xi=Ai*X(i-1)+Bi

操作1:修改某对(Ai,Bi)

操作2:求Xk

 

#include
#include
#include
#include
#define maxn 500005
#define mod 1000000007
#define lc now<<1
#define rc now<<1|1
using namespace std;

int n,m;


struct node
{
	int a,b;
	node(){}
	node(int a,int b):a(a),b(b){}
	node operator *(const node &nxt)const
	{
		return node(1ll*a*nxt.a%mod,(1ll*a*nxt.b%mod+b)%mod);
	}
}ele[maxn*10],tmp;

void insert(int now,int l,int r,int pos,node val)
{
	if(pos>r || pos>1;
	insert(lc,l,mid,pos,val);
	insert(rc,mid+1,r,pos,val);
	ele[now]=ele[rc]*ele[lc];
}

node Query(int now,int l,int r,int ql,int qr)
{
	if(ql>r || qr>1;
	return Query(rc,mid+1,r,ql,qr)*Query(lc,l,mid,ql,qr);
}

int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	int u;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n*5;i++) ele[i]=node(1,0);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&tmp.a,&tmp.b);
		insert(1,1,n,i,tmp);
	}
	
	char ch[10];
	for(int i=1;i<=m;i++)
	{
		scanf("%s",ch);
		if(ch[0]=='Q')
		{
			scanf("%d",&u);
			tmp=Query(1,1,n,1,u);
			printf("%d\n",(tmp.a+tmp.b)%mod);
		}
		else
		{
			scanf("%d",&u);
			scanf("%d%d",&tmp.a,&tmp.b);
			insert(1,1,n,u,tmp);
		}
	}
}
#include
#define maxn 30005
#define LL long long
#define inf (1ll<<50)
/*

calc(i+1,i+1)	cc	cc	dp[i-1]  dp[i]
0				-oo	-oo	dp[i-2]  dp[i-1]
-oo				0	-oo	dp[i-3]  dp[i-2]

*/
using namespace std;

int n,q;
int w[maxn],r[maxn],c1[maxn],c2[maxn],loc[maxn],lc[maxn];
inline bool cmp1(const int &u,const int &v){ return w[u] > w[v]; }
inline bool cmp2(const int &u,const int &v){ return r[u] > r[v]; }
LL f[70000][3][3],M;
LL calc(int x,int y)
{	if(x<=0 || y<=0 || x>n || y>n) return -inf;
	return 1ll * w[c1[x]] * r[c2[y]]; }
inline void mt(int x,int u=0,int v=0)
{  
	u = x<<1|1 , v = x<<1;
	memcpy(f[x],f[0],sizeof f[0]);
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++) if(f[u][i][j] > -inf)
			for(int k=0;k<3;k++) if(f[v][j][k] > -inf)
				f[x][i][k] = max(f[x][i][k] , f[u][i][j] + f[v][j][k]);
}
void upd(int x){ for(x>>=1;x;x>>=1) mt(x); }

int main()
{
	scanf("%d%d",&n,&q);
	for(M=1;M

 

你可能感兴趣的:(模板,数据结构,冲刺省选,矩阵优化)