题意
维护序列,需要支持区间加,区间乘,询问区间和。
题解
水题,直接线段树打两种标记,分别表示乘和加,下传标记稍微推一推即可。
#include<cstdio>
#define LL long long
const int maxn=200005;
struct node{
int L,R; LL sum,tag1,tag2;
node(int L=0,int R=0,LL sum=0,LL tag1=0,LL tag2=0):L(L),R(R),sum(sum),tag1(tag1),tag2(tag2){}
} seg[maxn*4];
int n,m;
LL MOD;
void maintain(int p){ seg[p].sum=(seg[p<<1].sum+seg[p<<1|1].sum)%MOD; }
void Pushdown(int p){
seg[p<<1].sum=(seg[p<<1].sum*seg[p].tag1%MOD+seg[p].tag2*(seg[p<<1].R-seg[p<<1].L+1)%MOD)%MOD;
seg[p<<1|1].sum=(seg[p<<1|1].sum*seg[p].tag1%MOD+seg[p].tag2*(seg[p<<1|1].R-seg[p<<1|1].L+1)%MOD)%MOD; // sum* seg[p*2].tag1 + seg[p*2].tag2
seg[p<<1].tag1=seg[p<<1].tag1*seg[p].tag1%MOD;
seg[p<<1].tag2=(seg[p<<1].tag2*seg[p].tag1%MOD+seg[p].tag2)%MOD; // (sum*seg[p*2].tag1+seg[p*2].tag2)*seg[p].tag1+seg[p].tag2
seg[p<<1|1].tag1=seg[p<<1|1].tag1*seg[p].tag1%MOD;
seg[p<<1|1].tag2=(seg[p<<1|1].tag2*seg[p].tag1%MOD+seg[p].tag2)%MOD; // sum* (seg[p*2].tag1*seg[p].tag1) + seg[p*2].tag2*seg[p].tag1+seg[p].tag2
seg[p].tag1=1; seg[p].tag2=0;
}
void seg_Build(int p,int L,int R){
seg[p]=node(L,R,0,1,0);
if(L==R){
scanf("%lld",&seg[p].sum); seg[p].sum%=MOD;
return;
}
int mid=(L+R)>>1;
seg_Build(p<<1,L,mid); seg_Build(p<<1|1,mid+1,R);
maintain(p);
}
void seg_Updata(int p,int L,int R,int w1,int w2){
if(seg[p].R<L||R<seg[p].L) return;
if(L<=seg[p].L&&seg[p].R<=R){
seg[p].sum=(seg[p].sum*w1%MOD+w2*(seg[p].R-seg[p].L+1)%MOD)%MOD;
seg[p].tag1=seg[p].tag1*w1%MOD;
seg[p].tag2=(seg[p].tag2*w1%MOD+w2)%MOD;
return;
}
if(seg[p].L==seg[p].R) return;
Pushdown(p);
seg_Updata(p<<1,L,R,w1,w2); seg_Updata(p<<1|1,L,R,w1,w2);
maintain(p);
}
LL seg_Query(int p,int L,int R){
if(seg[p].R<L||R<seg[p].L) return 0;
if(L<=seg[p].L&&seg[p].R<=R) return seg[p].sum;
if(seg[p].L==seg[p].R) return 0;
Pushdown(p);
return (seg_Query(p<<1,L,R)+seg_Query(p<<1|1,L,R))%MOD;
}
int main(){
scanf("%d%lld",&n,&MOD);
seg_Build(1,1,n);
scanf("%d",&m);
while(m--){
int t; scanf("%d",&t);
if(t==1){
int L,R,w; scanf("%d%d%d",&L,&R,&w);
seg_Updata(1,L,R,w,0);
}
if(t==2){
int L,R,w; scanf("%d%d%d",&L,&R,&w);
seg_Updata(1,L,R,1,w);
}
if(t==3){
int L,R; scanf("%d%d",&L,&R);
printf("%lld\n",seg_Query(1,L,R));
}
}
return 0;
}