zoukankan      html  css  js  c++  java
  • 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
    ",query(l,r,1,n,1)%mod);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    题解——[[SHOI2010]最小生成树]
    7.12周总结
    还有5个月就NOIP2019了,我干了什么
    【CQOI2018】破解D-H协议
    【SHOI2006】仙人掌
    【HNOI/AHOI2018】道路
    2019.11纪中集训 宋新波老师和曹天佑学长的勉励
    纪中集训2019.11.05
    【2019.10.25 OI-Killer的模拟赛】3.鸡数
    【华东师附国庆模拟赛】Day2 1.矩阵
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007130.html
Copyright © 2011-2022 走看看