洛谷P3373 【模板】线段树2

来源:互联网 发布:孢子mac中文版下载 编辑:程序博客网 时间:2024/06/05 16:33

这题有毒啊,敲了我一晚上加一早上,总算A了。

由于有加和乘两个操作,要用2个lazy数组。

核心难点就是2个lazy数组会相互影响。

因为乘影响加,加不影响乘,所以我们先算乘。

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <queue>#include <set>#include <map>#include <vector>#include <list>#define rep(i,m,n) for(int i=m;i<=n;i++)#define dop(i,m,n) for(int i=m;i>=n;i--)#define lowbit(x) (x&(-x)) #define ll long long#define INF 2147483647using namespace std;inline int read(){        //不写快读据说可能TLE   int s=0,w=1;   char ch=getchar();   while(ch<='0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();   return s*w;}const int maxn=100000;ll a[maxn+10],sum[(maxn<<2)+10],n,m,b,c,d,e,add[(maxn<<2)+10],mul[(maxn<<2)+10],mod;      //安全起见,都开long longvoid PushDown(int now,int m){    //now:线段编号,m:线段长度    if(mul[now]!=1){                        //乘法lazy数组都赋值为1      mul[now<<1]*=mul[now];      mul[now<<1|1]*=mul[now];      sum[now<<1]*=mul[now];      sum[now<<1|1]*=mul[now];      add[now<<1]*=mul[now];      add[now<<1|1]*=mul[now];      mul[now<<1]%=mod;      mul[now<<1|1]%=mod;      sum[now<<1]%=mod;      sum[now<<1|1]%=mod;      add[now<<1]%=mod;      add[now<<1|1]%=mod;      mul[now]=1;    }    if(add[now]){      add[now<<1]+=add[now];      add[now<<1|1]+=add[now];      sum[now<<1]+=add[now]*(m-(m>>1));      sum[now<<1|1]+=add[now]*(m>>1);      add[now<<1]%=mod;        //多mod几下,不会错      add[now<<1|1]%=mod;      sum[now<<1]%=mod;      sum[now<<1|1]%=mod;      add[now]=0;    }}void Build(int now,int l,int r){   //建树    mul[now]=1;    if(l==r) sum[now]=a[l];    else{      int mid=(l+r)>>1;      Build(now<<1,l,mid);      Build(now<<1|1,mid+1,r);      sum[now]=sum[now<<1]+sum[now<<1|1];    }}ll Query(int now,int l,int r,int wl,int wr){  //查询    if(l>wr||r<wl) return 0;    if(l>=wl&&r<=wr) return sum[now];    PushDown(now,r-l+1);    int mid=(l+r)>>1;    return (Query(now<<1,l,mid,wl,wr)%mod+Query(now<<1|1,mid+1,r,wl,wr)%mod)%mod;}void Change(int now,int l,int r,int wl,int wr,int p,int mode){   //改值,mode=1:加法,mode=2:乘法    if(l>wr||r<wl) return;          //如果当前区间不在需要改值的区间内,返回    if(l>=wl&&r<=wr){          //如果当前区间包括在需要改值的区间内,改这段的值,并标记lazy      if(mode) add[now]+=p,sum[now]+=p*(r-l+1),add[now]%=mod,sum[now]%=mod;              else mul[now]*=p,sum[now]*=p,add[now]*=p,add[now]%=mod,sum[now]%=mod,mul[now]%=mod;    //如果是乘法,要把加法lazy的值也改掉(乘法分配率)      return;    }    PushDown(now,r-l+1);    int mid=(l+r)>>1;    Change(now<<1,l,mid,wl,wr,p,mode);    Change(now<<1|1,mid+1,r,wl,wr,p,mode);    sum[now]=(sum[now<<1]+sum[now<<1|1])%mod;}int main(){    n=read();m=read();mod=read();    rep(i,1,n) a[i]=read();    Build(1,1,n);    rep(i,1,m){       b=read();       if(b==1){         c=read();d=read();e=read();         Change(1,1,n,c,d,e,0);       }       if(b==2){         c=read();d=read();e=read();         Change(1,1,n,c,d,e,1);       }       if(b==3){         c=read();d=read();         printf("%lld\n",Query(1,1,n,c,d));       }    }    return 0;}