大意:一个数组,三个操作,第一种是区间[a,b]每个数乘乘,第二种是区间[a,b]每个数加c,第三种是查询[a,b]区间的和并对p取摸。
两种操作就不能简单的只往下传标记。每次传乘法标记时,要把加法标记同时乘上乘法标记,例如某个区间先进来一个加法标记add,之后又进来一个乘法标记mul。
那么结果为(x+add)*mul=x*mul+add*mul。这样向下传标记的时候就相对独立。递归边界更新加法标记之前先乘上该节点的mul,左右儿子down的时候先将儿子的add乘上本节点的mul。
最后说一下sum,比如本节点的存在加法标记x和乘法标记y,并且是先加上x,再乘上y,则左儿子的sum要更新为(sum+x)*y。由于乘法标记传到本节点的时候更新了加法标记,x =x*y,所以sum[o<<1]=(左区间的长度*x)+sum[o<<1]*y。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 9 typedef long long LL; 10 11 #define N 100010 12 13 int n,m; 14 int askd,al,ar,ask; 15 LL p; 16 17 LL add[N<<2],sum[N<<2],mul[N<<2]; 18 19 void pushup(int now) 20 { 21 sum[now]=(sum[now<<1]+sum[now<<1|1])%p; 22 } 23 24 void pushdown(int now,int d) 25 { 26 if (add[now]!=0 || mul[now]!=1) 27 { 28 mul[now<<1]=mul[now<<1]*mul[now]%p; 29 mul[now<<1|1]=mul[now<<1|1]*mul[now]%p; 30 add[now<<1]=(add[now]+add[now<<1]*mul[now])%p; 31 add[now<<1|1]=(add[now]+add[now<<1|1]*mul[now])%p; 32 sum[now<<1]=(add[now]*(d-(d>>1))+sum[now<<1]*mul[now])%p; 33 sum[now<<1|1]=(add[now]*(d>>1)+sum[now<<1|1]*mul[now])%p; 34 add[now]=0; 35 mul[now]=1; 36 } 37 } 38 39 void build(int nowl,int nowr,int now) 40 { 41 sum[now]=0; 42 mul[now]=1; 43 if (nowl==nowr) 44 { 45 scanf("%lld",&sum[now]); 46 return ; 47 } 48 int mid=(nowl+nowr)>>1; 49 build(nowl,mid,now<<1); 50 build(mid+1,nowr,now<<1|1); 51 pushup(now); 52 } 53 54 void updata_mul(int nowl,int nowr,int now,int l,int r,int c) 55 { 56 if (nowl>=l && nowr<=r) 57 { 58 add[now]=add[now]*c%p; 59 sum[now]=sum[now]*c%p; 60 mul[now]=mul[now]*c%p; 61 return ; 62 } 63 pushdown(now,nowr-nowl+1); 64 int mid=(nowl+nowr)>>1; 65 if (l<=mid) 66 updata_mul(nowl,mid,now<<1,l,r,c); 67 if (r>mid) 68 updata_mul(mid+1,nowr,now<<1|1,l,r,c); 69 pushup(now); 70 } 71 72 void updata_add(int nowl,int nowr,int now,int l,int r,int c) 73 { 74 if (nowl>=l && nowr<=r) 75 { 76 add[now]=(add[now]+c)%p; 77 sum[now]=(sum[now]+c*(nowr-nowl+1))%p; 78 return ; 79 } 80 pushdown(now,nowr-nowl+1); 81 int mid=(nowl+nowr)>>1; 82 if (l<=mid) 83 updata_add(nowl,mid,now<<1,l,r,c); 84 if (r>mid) 85 updata_add(mid+1,nowr,now<<1|1,l,r,c); 86 pushup(now); 87 } 88 89 LL query(int nowl,int nowr,int now,int l,int r) 90 { 91 LL res(0); 92 if (nowl>=l && nowr<=r) 93 return sum[now]; 94 pushdown(now,nowr-nowl+1); 95 int mid=(nowl+nowr)>>1; 96 if (l<=mid) 97 res=(res+query(nowl,mid,now<<1,l,r))%p; 98 if (r>mid) 99 res=(res+query(mid+1,nowr,now<<1|1,l,r))%p; 100 return res; 101 } 102 103 int main() 104 { 105 scanf("%d%lld",&n,&p); 106 build(1,n,1); 107 scanf("%d",&m); 108 while (m--) 109 { 110 scanf("%d",&askd); 111 if (askd==1) 112 { 113 scanf("%d%d%d",&al,&ar,&ask); 114 updata_mul(1,n,1,al,ar,ask); 115 } 116 if (askd==2) 117 { 118 scanf("%d%d%d",&al,&ar,&ask); 119 updata_add(1,n,1,al,ar,ask); 120 } 121 if (askd==3) 122 { 123 scanf("%d%d",&al,&ar); 124 printf("%lld ",query(1,n,1,al,ar)); 125 } 126 } 127 return 0; 128 }