30分求助,找了俩小时错了
查看原帖
30分求助,找了俩小时错了
138608
白格Lifeplayer楼主2021/10/6 23:00
 #include <iostream>
 #include <cstdio>
 #define ll long long
 #define MAXN 100005
 using namespace std;
 ll ans[MAXN*4],a[MAXN],tagp[MAXN*4],tagm[MAXN*4];
 //ans记录各个节点的值,a记录初始的数值,tag记录那些没有往下做的add
 ll n,m,p;

 inline ll ls(ll f){return f<<1;}
 inline ll rs(ll f){return f<<1|1;}
 inline void push_up(int f){ans[f]=(ans[ls(f)]+ans[rs(f)])%p;}
 inline void build(ll l, ll r, ll f)
 {//l,r代表建树的左右端, f代表该区间的父节点
   if(l==r)
   {
     ans[f]=a[l];
     return ;
   }
   ll mid=(l+r)>>1;
   build(l,mid,ls(f));
   build(mid+1,r,rs(f));//把左右儿子的ans给算好
   push_up(f);//然后把两个儿子的ans给加一起
 }

 inline void cz(ll l, ll r, ll f, ll kp, ll km)
 {//头上不偷懒了,手下的人得干活了
   if(tagm[f]==0)tagm[f]=1;
   ans[f]=(ans[f]*km)%p;
   ans[f]=(ans[f]+kp*(r-l+1))%p;//先乘后加
   tagm[f]=(tagm[f]*km)%p;
   tagp[f]=(tagp[f]*km)%p;
   tagp[f]=(tagp[f]+kp)%p;//干完活又闲着了
 }
 inline void push_down(ll l, ll r, ll f)
 {
   ll mid=(l+r)>>1;
   if(tagm[f]==0)tagm[f]=1;
   cz(l, mid, ls(f), tagp[f], tagm[f]);
   cz(mid+1, r, rs(f), tagp[f], tagm[f]);//把两个儿子操作了
   tagm[f]=1;
   tagp[f]=0;//把懒标记消了(表示自己咩有偷懒)
 }
 inline void add(ll al, ll ar, ll l, ll r, ll f, ll k)
 {//al,ar代表需要修改的区间,l,r表示当前正在操作的区间,
   //f代表当前区间的父节点,k代表要加的数
   if(al<=l&&r<=ar)
   {
     tagp[f]+=k;
     ans[f]+=k*(r-l+1);
     return ;
   }
   if(tagm[f]==0)tagm[f]=1;
   //因为不会把ll数组初始化为1,所以只好每次可能用tagm前都初始化下QAQ
   if(tagp[f]!=0 || tagm[f]!=1)//如果现在这个点在偷懒
     push_down(l,r,f);
     //因为接下来要操作更小的区间,到它了还偷懒像样吗,让它拍拍屁股起来干活
   ll mid=(l+r)>>1;
   if(mid<ar)add(al,ar,mid+1,r,rs(f),k);//要是切割后的右区间碰到修改区间就干它
   if(al<=mid)add(al,ar,l,mid,ls(f),k);//要是切割后的左区间碰到修改区间就干它
   push_up(f);//子节点更新完还是要管管父节点的
 }

 inline void mult(ll ml, ll mr, ll l, ll r, ll f, ll k)
 {
   if(tagm[f]==0)tagm[f]=1;
   if(ml<=l&&r<=mr)
   {
     if(tagp[f]!=0)push_down(l,r,f);
     //因为遵循先乘后加的原则,所以如果有加的懒标记就得给它消了
     tagm[f]*=k;
     ans[f]*=k;
     return ;
   }
   if(tagp[f]!=0 || tagm[f]!=1)//如果现在这个点在偷懒
     push_down(l,r,f);
   ll mid=(l+r)>>1;
   if(mid<mr)mult(ml,mr,mid+1,r,rs(f),k);
   if(ml<=mid)mult(ml,mr,l,mid,ls(f),k);
   push_up(f);//老规矩
 }

 inline ll sum(ll sl, ll sr, ll l, ll r, ll f)
 {
   ll total=0;
   if(sl<=l&&r<=sr){return ans[f];}
   if(tagp[f]!=0)push_down(l,r,f);//上级查下来了,害搁这偷懒呢
   ll mid=(l+r)>>1;
   if(mid<sr)total+=sum(sl,sr,mid+1,r,rs(f));
   if(sl<=mid)total+=sum(sl,sr,l,mid,ls(f));
   return total%p;
 }

 int main()
 {
   // freopen("F:\\out.txt","w",stdout);
   cin >> n >> m >> p;
   for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
   build(1,n,1);
   ll cas,x,y,k;
   for(int cc=1;cc<=m;cc++)
   {
     scanf("%lld",&cas);
     switch(cas)
     {
       case 1:
       {
         scanf("%lld%lld%lld",&x,&y,&k);
         mult(x,y,1,n,1,k);
         break;
       }
       case 2:
       {
         scanf("%lld%lld%lld",&x,&y,&k);
         add(x,y,1,n,1,k);
         break;
       }
       case 3:
       {
         scanf("%lld%lld",&x,&y);
         cout << sum(x,y,1,n,1) <<endl;
         break;
       }
     }
   }
   // fclose(stdout);
   return 0;
 }

2021/10/6 23:00
加载中...