bzoj 1798(线段树)

 

传送门

分析:

因为同时涉及两种区间更新操作,故考虑用两种$lazytag$去打标记。

而在我们进行区间加和区间乘的时候,我们会发现,因为乘法的优先级较加法的优先级要高,因此,为了方便处理,我们优先选择下放乘法标记。

同时我们需要注意,在我们下放乘法标记$mul$的时候,如果当前区间存在加法标记$add$,则我们需要在$add$的基础上乘上$mul$

#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int mod;
typedef long long ll;
struct St{
    int rt,len;
    ll mul,sum,add;
}tr[maxn<<2];
int a[maxn];
void push_up(int rt){
    tr[rt].sum=(tr[rt<<1].sum+tr[rt<<1|1].sum)%mod;
}
void push_down(int rt){
    if(tr[rt].mul!=1){
        tr[rt<<1].mul=(tr[rt<<1].mul*tr[rt].mul)%mod;
        tr[rt<<1|1].mul=(tr[rt<<1|1].mul*tr[rt].mul)%mod;
        tr[rt<<1].add=(tr[rt<<1].add*tr[rt].mul)%mod;
        tr[rt<<1|1].add=(tr[rt<<1|1].add*tr[rt].mul)%mod;
        tr[rt<<1].sum=(tr[rt<<1].sum*tr[rt].mul)%mod;
        tr[rt<<1|1].sum=(tr[rt<<1|1].sum*tr[rt].mul)%mod;
        tr[rt].mul=1;
    }
    if(tr[rt].add){
        tr[rt<<1].add=(tr[rt<<1].add+tr[rt].add)%mod;
        tr[rt<<1|1].add=(tr[rt<<1|1].add+tr[rt].add)%mod;
        tr[rt<<1].sum=(tr[rt<<1].sum+tr[rt<<1].len*tr[rt].add%mod)%mod;
        tr[rt<<1|1].sum=(tr[rt<<1|1].sum+tr[rt<<1|1].len*tr[rt].add%mod)%mod;
        tr[rt].add=0;
    }
}
void build(int l,int r,int rt){
    tr[rt].len=r-l+1;
    tr[rt].mul=1;
    tr[rt].add=0;
    if(l==r){
        tr[rt].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    push_up(rt);
}
void update1(int L,int R,int l,int r,int rt,int x){
    if(L<=l&&R>=r){
        tr[rt].sum=tr[rt].sum+x*tr[rt].len%mod;
        tr[rt].add=(tr[rt].add+x)%mod;
        return ;
    }
    push_down(rt);
    int mid=(l+r)>>1;
    if(L<=mid) update1(L,R,l,mid,rt<<1,x);
    if(R>mid)  update1(L,R,mid+1,r,rt<<1|1,x);
    push_up(rt);
}
void update2(int L,int R,int l,int r,int rt,int x){
    if(L<=l&&R>=r){
        tr[rt].mul=tr[rt].mul*x%mod;
        tr[rt].add=tr[rt].add*x%mod;
        tr[rt].sum=tr[rt].sum*x%mod;
        return;
    }
    int mid=(l+r)>>1;
    push_down(rt);
    if(L<=mid) update2(L,R,l,mid,rt<<1,x);
    if(R>mid)  update2(L,R,mid+1,r,rt<<1|1,x);
    push_up(rt);
}
ll query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r){
        return tr[rt].sum%mod;
    }
    int mid=(l+r)>>1;
    push_down(rt);
    ll res=0;
    if(L<=mid) res=(query(L,R,l,mid,rt<<1)+res)%mod;
    if(R>mid) res=(query(L,R,mid+1,r,rt<<1|1)+res)%mod;
    return res;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&mod);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    scanf("%d",&m);
    while(m--){
        int op,l,r,num;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1){
            scanf("%d",&num);
            update2(l,r,1,n,1,num);
        }
        else if(op==2){
            scanf("%d",&num);
            update1(l,r,1,n,1,num);
        }
        else{
            printf("%lld\n",query(l,r,1,n,1)%mod);
        }
    }
    return 0;
}
posted @ 2019-05-29 21:36  ChenJr  阅读(218)  评论(0编辑  收藏  举报