# 题意
给定长度为n的序列,有3个操作,分别是
1)给定一个区间[l,r]区间所有数同乘一个数
2)给定区间[l,r]区间所有数同时加一个数
3)给定区间[l,r]问区间所有数的和mod P后的结果
# 题解
pushdown的时候有两个延迟标记,不需要根据操作来分开写,
当乘的时候相当于+0,加的时候乘1
更新延迟标记的时候假设当前的
(x*mul+add)*a=x*mul*a+add*a
标记的更新:
mul=mul*a
add=add*mul+b
1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N=1e5+10; 5 int n,p; 6 int a[N]; 7 struct node{ 8 int l,r; 9 ll sum,add,mul; 10 }tr[N*4]; 11 void pushup(int u){ 12 tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p; 13 } 14 void cal(node &t,int add,int mul){ 15 t.sum=((ll)t.sum*mul+(ll)(t.r-t.l+1)*add)%p; 16 t.mul=((ll)t.mul*mul)%p; 17 t.add=((ll)t.add*mul + add)%p; 18 } 19 void pushdown(int u) { 20 cal(tr[u<<1],tr[u].add,tr[u].mul); 21 cal(tr[u<<1|1],tr[u].add,tr[u].mul); 22 tr[u].add=0,tr[u].mul=1; 23 } 24 void build(int u,int l,int r){ 25 if(l==r){ 26 tr[u]={l,r,a[r],0,1}; 27 return; 28 } 29 tr[u]={l,r,0,0,1};//pushup 只会更新sum的值,要赋值 30 int mid= l + r >>1; 31 build(u<<1,l,mid); 32 build(u<<1|1,mid+1,r); 33 pushup(u); 34 } 35 void change(int u,int l,int r,int ad,int mu){ 36 if(tr[u].l>=l && tr[u].r<=r){ 37 cal(tr[u],ad,mu); 38 return; 39 } 40 pushdown(u); 41 int mid=tr[u].l+tr[u].r>>1; 42 if(l <= mid) change(u<<1,l,r,ad,mu); 43 if(r>mid) change(u<<1|1,l,r,ad,mu); 44 pushup(u); 45 } 46 ll ask(int u,int l,int r){ 47 if(tr[u].l>=l && tr[u].r <=r) 48 return tr[u].sum; 49 pushdown(u); 50 int mid=tr[u].l+tr[u].r>>1; 51 ll res=0; 52 if(l<=mid) res=ask(u<<1,l,r); 53 if(r>mid) res=(res+ask(u<<1|1,l,r))%p; 54 return res; 55 } 56 int main(){ 57 cin>>n>>p; 58 for(int i=1;i<=n;i++) 59 cin>>a[i]; 60 build(1,1,n); 61 int m; 62 cin>>m; 63 while(m--){ 64 int op,l,r,c; 65 cin>>op>>l>>r; 66 if(op==1){ 67 cin>>c; 68 change(1,l,r,0,c); 69 } 70 else if(op==2){ 71 cin>>c; 72 change(1,l,r,c,1); 73 } 74 else { 75 cout<<ask(1,l,r)%p<<endl; 76 } 77 } 78 }