【模板】线段树区间加、区间乘、区间和、区间平方和

  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     char ch=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 }

 

posted @ 2018-12-02 23:33  Whiteying  阅读(907)  评论(1编辑  收藏  举报