我一脚踹他下去。

先致敬 houzhe 学长经典:

我看到我的队友写了个又臭又长的线段树,维护了一堆 tag,于是一脚把他踹下去,写了个线段树维护矩阵,然后就过了。

回到这题,题意即为求一段连续的版本 \([x,y]\) 中,所有版本的区间 \([l,r]\) 的值的平方和。

首先显然可以变成 \([1,y]\) 版本的答案减去 \([1,x]\) 版本的答案。然后变成一个历史版本和问题。解决历史版本和问题自然会想到维护矩阵。当然你打 tag 也是可以的,但是这样的话建议还是从矩阵的角度去推更新,否则很容易出问题。

具体地,SGT 上每个位置维护一个 \(4\times 4\) 的矩阵,记录区间和,区间平方和,区间长度和区间历史版本和四个量,把 \(\sum(a_i+k)^2\) 套路化地拆成 \(\sum a_i^2+\sum a_i\times k+len\times k^2\),这也是一个矩阵很好维护的形式。每做完一次操作之后更新历史和即可。

细节不是很多,需要注意的有:

  • tag 的矩阵初始值是单位矩阵而不是全 \(0\) 矩阵。

  • \(a_i\) 和更新的 \(x\) 都可能是负数。

结束了。跑的还挺快……吗?至少过了而且不是最劣解。/kk

code:

点击查看代码
int n,m,q,a[N],ans[N];
struct node{int l,r,x;}b[N];
struct Node{int l,r,s,id;};
vector<Node> g[N];
il int Mod(int x,int y){return x+y>=mod?x+y-mod:x+y;}
struct SGT{
	struct mat{
		int a[4][4];
		mat(){mems(a,0);}
		il void reset(){mems(a,0);rep(i,0,3)a[i][i]=1;}
		il mat operator*(const mat &rhs)const{
			mat r;
			rep(k,0,3)rep(i,0,3)rep(j,0,3)r.a[i][j]=Mod(r.a[i][j],1ll*a[i][k]*rhs.a[k][j]%mod);
			return r;
		}
		il mat operator+(const mat &rhs)const{
			mat r;
			rep(i,0,3)rep(j,0,3)r.a[i][j]=Mod(a[i][j],rhs.a[i][j]);
			return r;
		}
	};
	struct Tnode{mat x,tag;}tr[N<<2];
	il void pushup(int o){tr[o].x=tr[o<<1].x+tr[o<<1|1].x;}
	il void reset(int o,mat &k){tr[o].x=tr[o].x*k,tr[o].tag=tr[o].tag*k;}
	il void pushdown(int o){reset(o<<1,tr[o].tag),reset(o<<1|1,tr[o].tag),tr[o].tag.reset();}
	void build(int l,int r,int o){
		tr[o].tag.reset();
		if(l==r)return tr[o].x.a[0][0]=Mod(a[l],mod),tr[o].x.a[0][1]=1ll*a[l]*a[l]%mod,tr[o].x.a[0][2]=1,void();
		int mid=(l+r)>>1;
		build(l,mid,o<<1),build(mid+1,r,o<<1|1);
		pushup(o);
	}
	void update(int l,int r,int o,int x,int y,mat k){
		if(l>=x&&r<=y)return reset(o,k);
		pushdown(o);
		int mid=(l+r)>>1;
		if(x<=mid)update(l,mid,o<<1,x,y,k);
		if(y>mid)update(mid+1,r,o<<1|1,x,y,k);
		pushup(o);
	}
	int query(int l,int r,int o,int x,int y){
		if(r<x||l>y)return 0;
		if(l>=x&&r<=y)return tr[o].x.a[0][3];
		pushdown(o);
		int mid=(l+r)>>1;
		return Mod(query(l,mid,o<<1,x,y),query(mid+1,r,o<<1|1,x,y));
	}
}T;
void Yorushika(){
	scanf("%d%d%d",&n,&m,&q),m++;
	rep(i,1,n)scanf("%d",&a[i]);
	rep(i,2,m)scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].x);
	rep(i,1,q){
		int l,r,x,y;scanf("%d%d%d%d",&l,&r,&x,&y);
		g[x].eb((Node){l,r,-1,i}),g[y+1].eb((Node){l,r,1,i});
	}
	T.build(1,n,1),b[1]={1,1,0};
	SGT::mat x;x.reset();
	rep(i,1,m){
		SGT::mat tmp;int x=b[i].x;
		tmp.a[0][0]=1,tmp.a[0][1]=Mod(2ll*x%mod,mod);
		tmp.a[1][1]=1;
		tmp.a[2][0]=Mod(x,mod),tmp.a[2][1]=1ll*x*x%mod,tmp.a[2][2]=1;
		tmp.a[3][3]=1;
		T.update(1,n,1,b[i].l,b[i].r,tmp);
		tmp.reset(),tmp.a[1][3]=1;
		T.reset(1,tmp);
		for(Node j:g[i])ans[j.id]=Mod(ans[j.id],Mod(mod,T.query(1,n,1,j.l,j.r)*j.s));
	}
	rep(i,1,q)printf("%d\n",ans[i]);
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}
posted @ 2023-12-04 18:16  yinhee  阅读(35)  评论(0)    收藏  举报