线段树 在线进行两种不同的修改 洛谷P3373

题目链接:https://www.luogu.org/problem/P3373

题意:线段树操作,操作一区间内每个数乘k,操作二区间每个数+k,操作三查询区间数的和(还会输入一个p,要求的是模p后的结果)

分析:要用到两个update函数,两种lazytag这个很容易想到了,但是pushdown函数的书写却很头疼,不知道一会加一会乘该怎么标记下传

我们仔细分析会发现,当进行加法操作时,加法优先级低,只改变自身lazytag即可

进行乘法操作时,乘法优先级高,会同时改变加法和乘法的lazytag

故我们在标记下传的时候先进行乘法再进行加法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=1<<30;
const int maxn=1e5+7;
const double pi=acos(-1);
const int mod=100;
#define meminf(a) memset(a,0x3f,sizeof(a))
#define mem0(a) memset(a,0,sizeof(a))
#define ls rt<<1
#define rs rt<<1|1
#define mid (l+r)>>1
ll dat[maxn<<2],a[maxn<<2],lazyadd[maxn<<2],lazymul[maxn<<2];
int n_,m,p;

void pushup(int rt){
    dat[rt]=(dat[ls]+dat[rs])%p;
}

void pushdown(int rt,int l,int r){
    dat[ls]=((dat[ls]*lazymul[rt])%p+lazyadd[rt]*(r-l)/2+p)%p;
    dat[rs]=((dat[rs]*lazymul[rt])%p+lazyadd[rt]*(r-l)/2+p)%p;
    lazymul[ls]=(lazymul[rt]*lazymul[ls])%p;
    lazymul[rs]=(lazymul[rt]*lazymul[rs])%p;
    lazyadd[ls]=((lazymul[rt]*lazyadd[ls])%p+lazyadd[rt]+p)%p;
    lazyadd[rs]=((lazymul[rt]*lazyadd[rs])%p+lazyadd[rt]+p)%p;
    lazyadd[rt]=0;
    lazymul[rt]=1;
}

void build(int l,int r,int rt){
    lazymul[rt]=1,lazyadd[rt]=0;
    if(l==r-1){
        dat[rt]=a[l];
        return;
    }
    build(l,mid,ls);
    build(mid,r,rs);
    pushup(rt);
}
//我们设的乘法优先级高于加法,所以这里要一并更新加法的 
void update1(int l,int r,int s,int t,int rt,ll c){
    if(s<=l&&r<=t){
        dat[rt]=(dat[rt]*c)%p;
        lazymul[rt]=(lazymul[rt]*c)%p;
        lazyadd[rt]=(lazyadd[rt]*c)%p;
        return;//这里是关键 
    }
    pushdown(rt,l,r);//递归到子节点前先标记下传 
    if(s<mid) update1(l,mid,s,t,ls,c);
    if(t>mid) update1(mid,r,s,t,rs,c);
    pushup(rt);
}

void update2(int l,int r,int s,int t,int rt,ll c){
    if(s<=l&&r<=t){
        dat[rt]=(dat[rt]+c*(r-l)+p)%p;
        lazyadd[rt]=(lazyadd[rt]+c+p)%p;
        return;//这里是关键 
    }
    pushdown(rt,l,r);//递归到子节点前先标记下传 
    if(s<mid) update2(l,mid,s,t,ls,c);
    if(t>mid) update2(mid,r,s,t,rs,c);
    pushup(rt);
}

ll query(int l,int r,int s,int t,int rt){
    ll ans=0;
    if(s<=l&&r<=t){
        return (dat[rt]+p)%p;
    }
    pushdown(rt,l,r);
    if(s<mid) ans=(ans+query(l,mid,s,t,ls))%p;
    if(t>mid) ans=(ans+query(mid,r,s,t,rs))%p;
    return ans;
}

int main(){
      scanf("%d%d%d",&n_,&m,&p);
      int n=1;
      for(int i=1;i<=n_;i++)scanf("%lld",&a[i]);
      while(n<n_)n<<=1;
      build(1,n+1,1);
      for(int i=1;i<=m;i++){
          int opt,x,y;ll k;
          scanf("%d%d%d",&opt,&x,&y);
          if(opt==1){
              scanf("%lld",&k);
              update1(1,n+1,x,y+1,1,k);
          }
        else if(opt==2){
            scanf("%lld",&k);
            update2(1,n+1,x,y+1,1,k);
        }
        else if(opt==3){
            printf("%lld\n",query(1,n+1,x,y+1,1)%p);
        }  
      }
    return 0;
}

 

posted @ 2019-08-20 10:45  清酒令  阅读(213)  评论(0编辑  收藏  举报