luogu 3373
线段树懒标记维护乘与加
每个节点的sum,一定是这个点所带的懒标记经过所有运算后最终的sum值,这种题目做起来一定要系统化,必须定好标准,决不能混乱。
每次询问到一个点,如果这个点不用深入下去,则直接打上标记即可,同时更新这个点的sum值,否则的话需要把标记传给它的左右儿子,然后它的标记清0。一定要养成无论是修改还是询问一旦进入子树必须先push_down的好习惯,最后别忘了结束位置再根据它的左右节点sum值update一下。
一个要注意的地方,由于有两种标记,故也要定好两种标记的优先级。
乘法优于加法,即如果一个地方打了一个乘法标记,那么它的乘法标记、加法标记、sum值都得乘这个标记值。如果打了一个加法标记,则只需要修改这个点的加法标记与sum值,无须修改乘法标记,切勿优先标准混乱。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL N=110000;
LL n,m,p,op,x,y,k,mo;
struct node{
LL sum,add,mul;
}t[N*4];
void update(LL w){
t[w].sum=(t[w*2].sum+t[w*2+1].sum)%mo;
}
void down_push(LL w,LL l,LL r){
LL mid=(l+r)/2;
t[w*2].mul=(t[w*2].mul*t[w].mul)%mo;
t[w*2].add=(t[w*2].add*t[w].mul+t[w].add)%mo;
t[w*2].sum=(t[w*2].sum*t[w].mul+t[w].add*(mid-l+1))%mo;
t[w*2+1].mul=(t[w*2+1].mul*t[w].mul)%mo;
t[w*2+1].add=(t[w*2+1].add*t[w].mul+t[w].add)%mo;
t[w*2+1].sum=(t[w*2+1].sum*t[w].mul+t[w].add*(r-mid))%mo;
t[w].mul=1;
t[w].add=0;
}
void build(LL w,LL l,LL r){
t[w].mul=1;
if(l==r){
cin>>t[w].sum;
return;
}
LL mid=(l+r)/2;
build(w*2,l,mid);
build(w*2+1,mid+1,r);
update(w);
}
void modifymul(LL w,LL l,LL r,LL ll,LL rr,LL z){
if(ll<=l&&rr>=r){
t[w].mul=t[w].mul*z%mo;
t[w].sum=t[w].sum*z%mo;
t[w].add=t[w].add*z%mo;
return;
}
down_push(w,l,r);
LL mid=(l+r)/2;
if(ll<=mid)modifymul(w*2,l,mid,ll,rr,z);
if(rr>mid)modifymul(w*2+1,mid+1,r,ll,rr,z);
update(w);
}
void modifyadd(LL w,LL l,LL r,LL ll,LL rr,LL z){
if(ll<=l&&rr>=r){
t[w].sum=(t[w].sum+z*(r-l+1))%mo;
t[w].add=(t[w].add+z)%mo;
return;
}
down_push(w,l,r);
LL mid=(l+r)/2;
if(ll<=mid)modifyadd(w*2,l,mid,ll,rr,z);
if(rr>mid)modifyadd(w*2+1,mid+1,r,ll,rr,z);
update(w);
}
LL query(LL w,LL l,LL r,LL ll,LL rr){
if(ll<=l&&rr>=r)return t[w].sum;
down_push(w,l,r);
LL ans=0;
LL mid=(l+r)/2;
if(ll<=mid)ans+=query(w*2,l,mid,ll,rr);
if(rr>mid)ans+=query(w*2+1,mid+1,r,ll,rr);
return ans%mo;
}
int main(){
cin>>n>>m>>mo;
build(1,1,n);
while(m--){
cin>>op;
if(op==1){
cin>>x>>y>>k;
modifymul(1,1,n,x,y,k);
}
if(op==2){
cin>>x>>y>>k;
modifyadd(1,1,n,x,y,k);
}
if(op==3){
cin>>x>>y;
cout<<query(1,1,n,x,y)<<endl;
}
}
return 0;
}