这题写了我两个小时,在cf延时的15分钟内调出来了,直呼内行
D 线段树 区间加,区间乘,区间查询,区间覆盖
给个节点用k*x+val 表示lazy更新 初始叶子节点k=1 val=a[l] 其他 k=1 val=0
一个mul数组,记录每个节点的前面的系数k,val数组记录后面val的值 sum数组记录区间和,因为询问的是区间和
每次区间乘了一个k:
某个节点记录:
mul[id]*=k
val[id]*=k
sum[id]*=k
mul[id]=k*mul[id]%mod; val[id]=k*val[id]%mod; sum[id]=k*sum[id]%mod;
区间加了一个k:
val[id]+=k
sum[id]+k*(r-l+1) (l,r是某个节点的信息)
add(val[id],k); add(sum[id],k*(r-l+1)%mod);
区间覆盖:(惊天妙手,突然想到的处理方式)
mul[id]=0; val[id]=k; sum[id]=k*(r-l+1)
lazy更新:相当于某个节点同时来k倍系数以及加了个 后缀的x值
假设k、x是由id的父亲节点传来,
mul[id]*=k;
val[id]=x+k*val[id]
sum[id]=sum[id]k+x(r-l+1)
int root=id,len=r-l+1;
ll p=mod; mul[id<<1]=mul[id]*mul[id<<1]%mod; val[id<<1]=(val[id]+val[id<<1]*mul[id]%mod)%mod; sum[root<<1]=(sum[root<<1]*mul[root]%p+val[root]*(len-(len>>1))%p)%p; mul[id<<1|1]=mul[id]*mul[id<<1|1]%mod; val[id<<1|1]=(val[id]+val[id<<1|1]*mul[id]%mod)%mod; sum[root<<1|1]=(sum[root<<1|1]*mul[root]%p+val[root]*(len>>1)%p)%p;
代码:
#pragma GCC optimize(2) #include<bits/stdc++.h> #define ll long long #define maxn 1005 #define inf 1e9 #define pb push_back #define rep(i,a,b) for(int i=a;i<=b;i++) #define per(i,a,b) for(int i=a;i>=b;i--) using namespace std; inline ll read() { ll x=0,w=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();} while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return w==1?x:-x; } const int N=2e5+10; ll n,m,mod; int mx; struct node { int ty,l,r; ll k; }a[N]; ll mul[4*N],val[4*N],sum[4*N],t[N]; int st[4*N]; void add(ll &x,ll y) { x=(x+y)%mod; } void build(int id,int l,int r) { mul[id]=1; if(l==r){ sum[id]=t[l]; return ; } int mid=l+r>>1; build(id<<1,l,mid); build(id<<1|1,mid+1,r); sum[id]=(sum[id<<1]+sum[id<<1|1])%mod; } void pushdown(int id,int l,int r) { int mid=l+r>>1; if(mul[id]==1&&val[id]==0) return; int root=id,len=r-l+1; ll p=mod; mul[id<<1]=mul[id]*mul[id<<1]%mod; val[id<<1]=(val[id]+val[id<<1]*mul[id]%mod)%mod; sum[root<<1]=(sum[root<<1]*mul[root]%p+val[root]*(len-(len>>1))%p)%p; mul[id<<1|1]=mul[id]*mul[id<<1|1]%mod; val[id<<1|1]=(val[id]+val[id<<1|1]*mul[id]%mod)%mod; sum[root<<1|1]=(sum[root<<1|1]*mul[root]%p+val[root]*(len>>1)%p)%p; mul[id]=1,val[id]=0; } ll qu(int id,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) return sum[id]; int mid=l+r>>1; ll ans=0; pushdown(id,l,r); if(ql<=mid) ans=qu(id<<1,l,mid,ql,qr); if(qr>mid) add(ans,qu(id<<1|1,mid+1,r,ql,qr)); //sum[id]=(sum[id<<1|1]+sum[id<<1])%mod; return ans; } void up(int id,int l,int r,int ql,int qr,ll k,int ty) { if(ql<=l&&r<=qr){ if(ty==1){ //printf("id:%d sum[id]:%lld\n",id,sum[id]); add(val[id],k); add(sum[id],k*(r-l+1)%mod); //printf("id:%d sum[id]:%lld\n",id,sum[id]); } else if(ty==2){ mul[id]=k*mul[id]%mod; val[id]=k*val[id]%mod; sum[id]=k*sum[id]%mod; } else if(ty==3){ st[id]=-1; mul[id]=0; val[id]=k; sum[id]=k*(r-l+1)%mod; } else{ mul[id]=1,val[id]=k; sum[id]=k*(r-l+1)%mod; } return ; } pushdown(id,l,r); int mid=l+r>>1; if(ql<=mid) up(id<<1,l,mid,ql,qr,k,ty); if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,k,ty); sum[id]=(sum[id<<1|1]+sum[id<<1])%mod; } int main() { n=read(),m=read(),mod=read(); mx=n; rep(i,1,n) t[i]=read(); for(int i=1;i<=m;++i){ scanf("%d%d",&a[i].ty,&a[i].l); if(a[i].ty==5) scanf("%d",&a[i].r); else if(a[i].ty==4) mx++; else scanf("%d%lld",&a[i].r,&a[i].k),a[i].k%=mod; a[i].r=min(a[i].r,mx); a[i].r=min(a[i].r,mx); } build(1,1,mx); int now=n; for(int i=1;i<=m;++i){ if(a[i].ty==1){ up(1,1,mx,a[i].l,a[i].r,a[i].k,1); } else if(a[i].ty==2){ up(1,1,mx,a[i].l,a[i].r,a[i].k,2); } else if(a[i].ty==3){ up(1,1,mx,a[i].l,a[i].r,a[i].k,3); } else if(a[i].ty==4){ up(1,1,mx,++now,now,a[i].l,4); } else if(a[i].ty==5){ printf("%lld\n",qu(1,1,mx,a[i].l,a[i].r)); } } } /* 5 6 9555 1 1 1 1 1 3 2 5 5 5 1 5 1 1 4 5 1 1 5 5 1 3 5 5 5 1 4 5 12 9555 1 1 1 1 1 3 2 5 5 1 1 4 5 1 1 5 5 1 3 5 5 5 1 4 2 1 5 5 2 2 2 5 3 5 5 5 3 3 5 5 5 1 3 1 2 3 5 5 1 3 */