[模板]線段樹區間加、區間乘、區間和、區間平方和
阿新 • • 發佈:2018-12-02
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define L(x) x<<1 //左兒子 x*2 4 #define R(x) x<<1|1 //右兒子 x*2+1 5 const int maxn =1e5+5; 6 using namespace std; 7 LL n,m,num[maxn]; 8 LL mod; //膜數 9 inline LL read() { 10 LL x=0,f=1; 11 charch=getchar(); 12 while(ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar(); 13 while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); 14 return x*f; 15 } 16 struct T { 17 LL l,r; 18 LL sum,add,mul; 19 } tree[maxn<<2];//注意開long long 和四倍空間 20 inline void update(LL p) {21 tree[p].sum=(tree[L(p)].sum+tree[R(p)].sum)%mod; 22 return; 23 } 24 inline void spread(LL p) { 25 LL mid=(tree[p].l+tree[p].r)>>1; 26 if(tree[p].mul!=1) { 27 tree[L(p)].mul=(tree[L(p)].mul*tree[p].mul)%mod; 28 tree[R(p)].mul=(tree[R(p)].mul*tree[p].mul)%mod;29 tree[L(p)].add=(tree[L(p)].add*tree[p].mul)%mod; 30 tree[R(p)].add=(tree[R(p)].add*tree[p].mul)%mod; 31 tree[L(p)].sum=(tree[L(p)].sum*tree[p].mul)%mod; 32 tree[R(p)].sum=(tree[R(p)].sum*tree[p].mul)%mod; 33 tree[p].mul=1; 34 } 35 if(tree[p].add) { 36 tree[L(p)].add=(tree[L(p)].add+tree[p].add)%mod; 37 tree[R(p)].add=(tree[R(p)].add+tree[p].add)%mod; 38 tree[L(p)].sum=(tree[L(p)].sum+tree[p].add*(mid-tree[p].l+1))%mod; 39 tree[R(p)].sum=(tree[R(p)].sum+tree[p].add*(tree[p].r-mid))%mod;//tree[p].r-mid不加1 40 tree[p].add=0; 41 } 42 return; 43 } 44 inline void build(LL l,LL r,LL p) {//建樹 45 tree[p].l=l,tree[p].r=r,tree[p].mul=1; 46 if(l==r) { 47 tree[p].sum=num[l]; 48 tree[p].mul=1; 49 return; 50 } 51 LL mid=(tree[p].l+tree[p].r)>>1; 52 build(l,mid,L(p)); 53 build(mid+1,r,R(p)); 54 update(p); 55 return; 56 } 57 inline void change1(LL l,LL r,LL p,LL v) {//區間增值 58 if(tree[p].l==l&&tree[p].r==r) { 59 tree[p].add=(tree[p].add+v)%mod; 60 tree[p].sum=(tree[p].sum+v*(r-l+1))%mod; 61 return; 62 } 63 spread(p); 64 LL mid=(tree[p].l+tree[p].r)>>1; 65 if(r<=mid) change1(l,r,L(p),v); 66 else if(l>mid) change1(l,r,R(p),v); 67 else change1(l,mid,L(p),v),change1(mid+1,r,R(p),v); 68 update(p); 69 return; 70 } 71 inline void change2(LL l,LL r,LL p,LL v) {//區間乘法 72 73 if(tree[p].l==l&&tree[p].r==r) { 74 tree[p].mul=(tree[p].mul*v)%mod; 75 tree[p].sum=(tree[p].sum*v)%mod; 76 tree[p].add=(tree[p].add*v)%mod; 77 return; 78 } 79 spread(p); 80 LL mid=(tree[p].l+tree[p].r)>>1; 81 if(r<=mid) change2(l,r,L(p),v); 82 else if(l>mid) change2(l,r,R(p),v); 83 else change2(l,mid,L(p),v),change2(mid+1,r,R(p),v); 84 update(p); 85 return; 86 } 87 inline LL ask_sum1(LL l,LL r,LL p) {//區間和 88 if(tree[p].l==l&&tree[p].r==r) { 89 return tree[p].sum%mod; 90 } 91 spread(p); 92 LL mid=(tree[p].l+tree[p].r)>>1; 93 if(r<=mid) return ask_sum1(l,r,L(p))%mod; 94 else if(l>mid) return ask_sum1(l,r,R(p))%mod; 95 else return (ask_sum1(l,mid,L(p))%mod+ask_sum1(mid+1,r,R(p))%mod)%mod; 96 } 97 98 inline LL ask_sum2(LL l,LL r,LL p) {//區間平方和 99 if(tree[p].l==tree[p].r) { 100 return tree[p].sum*tree[p].sum; 101 } 102 spread(p); 103 LL mid=(tree[p].l+tree[p].r)>>1; 104 if(r<=mid) return ask_sum2(l,r,L(p)); 105 else if(l>mid) return ask_sum2(l,r,R(p)); 106 else return ask_sum2(l,mid,L(p))+ask_sum2(mid+1,r,R(p)); 107 } 108 109 LL opt,l,r,v; 110 int main() { 111 n=read(),m=read(); 112 mod=read(); 113 for(int i=1; i<=n; i++) num[i]=read(); 114 build(1,n,1); 115 while(m--) { 116 opt=read(); 117 if(opt==3) { 118 l=read(),r=read(); 119 printf("%lld\n",ask_sum1(l,r,1)%mod);//詢問區間和 120 } 121 if(opt==4) { 122 l=read(),r=read(); 123 printf("%lld\n",ask_sum2(l,r,1)%mod);//詢問區間平方和 124 } 125 if(opt==1) { 126 l=read(),r=read(),v=read(); 127 change2(l,r,1,v);//區間乘 128 } 129 if(opt==2) { 130 l=read(),r=read(),v=read(); 131 change1(l,r,1,v);//區間加 132 } 133 } 134 return 0; 135 }