• Luogu P3373 【模板】线段树 2


    这还是比较简单的线段树模板题吧

    更多的是给一个思路,当维护多种需要Lazy Tag的操作时顺序问题

    这里的话加法和查询都可以参照区间加法模板题Sol

    主要是当标记下传的时候,要注意先处理乘法在处理加法

    Why?

    因为显然乘法的优先级比加法高,如果先加后乘就会爆掉

    例如:10+6*233

    如果先算加法那么就是16*233,那么显然是错的

    而且就算是这样的情况如(10+100)*233

    也可以把乘法标记先传给加法化成10*233+100*233(乘法分配律的原理,小学数学)

    然后规定好顺序就可以直接套线段树的板子了

    CODE

    #include<cstdio>
    using namespace std;
    typedef long long LL;
    const LL N=100005;
    struct segtree
    {
        LL sum,add,mul;
    }tree[N<<2];
    LL n,m,p,a[N],opt,x,y,z;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(LL &x)
    {
        x=0; char ch=tc();
        while (ch<'0'||ch>'9') ch=tc();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline void write(LL x)
    {
        if (x/10) write(x/10);
        putchar(x%10+'0');
    }
    inline void up(LL root)
    {
        tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%p;
    }
    inline void down(LL root,LL l,LL r)
    {
        if (tree[root].add||tree[root].mul!=1)
        {
            tree[root<<1].mul=(tree[root<<1].mul*tree[root].mul)%p;
            tree[root<<1|1].mul=(tree[root<<1|1].mul*tree[root].mul)%p;
            tree[root<<1].add=(tree[root<<1].add*tree[root].mul)%p;
            tree[root<<1|1].add=(tree[root<<1|1].add*tree[root].mul)%p;
            tree[root<<1].sum=(tree[root<<1].sum*tree[root].mul)%p;
            tree[root<<1|1].sum=(tree[root<<1|1].sum*tree[root].mul)%p;
            tree[root].mul=1;
            tree[root<<1].add=(tree[root<<1].add+tree[root].add)%p;
            tree[root<<1|1].add=(tree[root<<1|1].add+tree[root].add)%p;
            tree[root<<1].sum=(tree[root<<1].sum+tree[root].add*l)%p;
            tree[root<<1|1].sum=(tree[root<<1|1].sum+tree[root].add*r)%p;
            tree[root].add=0;
        }
    }
    inline void build(LL root,LL l,LL r)
    {
        tree[root].mul=1;
        if (l==r)
        {
            tree[root].sum=a[l];
            return;
        }
        LL mid=l+r>>1;
        build(root<<1,l,mid); build(root<<1|1,mid+1,r);
        up(root);
    }
    inline void modify_mul(LL root,LL l,LL r,LL beg,LL end,LL k)
    {
        if (l>=beg&&r<=end)
        {
            tree[root].mul=(tree[root].mul*k)%p;
            tree[root].add=(tree[root].add*k)%p;
            tree[root].sum=(tree[root].sum*k)%p;
            return;
        }
        LL mid=l+r>>1;
        down(root,mid-l+1,r-mid);
        if (beg<=mid) modify_mul(root<<1,l,mid,beg,end,k);
        if (mid<end) modify_mul(root<<1|1,mid+1,r,beg,end,k);
        up(root);
    }
    inline void modify_add(LL root,LL l,LL r,LL beg,LL end,LL k)
    {
        if (l>=beg&&r<=end)
        {
            tree[root].add=(tree[root].add+k)%p;
            tree[root].sum=(tree[root].sum+k*(r-l+1))%p;
            return;
        }
        LL mid=l+r>>1;
        down(root,mid-l+1,r-mid);
        if (beg<=mid) modify_add(root<<1,l,mid,beg,end,k);
        if (mid<end) modify_add(root<<1|1,mid+1,r,beg,end,k);
        up(root);
    }
    inline LL query(LL root,LL l,LL r,LL beg,LL end)
    {
        if (l>=beg&&r<=end) return tree[root].sum;
        LL mid=l+r>>1,res=0;
        down(root,mid-l+1,r-mid);
        if (beg<=mid) res=(res+query(root<<1,l,mid,beg,end))%p;
        if (mid<end) res=(res+query(root<<1|1,mid+1,r,beg,end))%p;
        up(root);
        return res;
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register LL i;
        read(n); read(m); read(p);
        for (i=1;i<=n;++i)
        read(a[i]);
        build(1,1,n);
        while (m--)
        {
            read(opt); read(x); read(y);
            if (opt==1) read(z),modify_mul(1,1,n,x,y,z%p);
            if (opt==2) read(z),modify_add(1,1,n,x,y,z%p);
            if (opt==3) write(query(1,1,n,x,y)),putchar('
    ');
        }
        return 0;
    }
    

    此题和这道题基本类似完全一样,双倍经验即可(但我打了两次,权当熟练,毕竟线段树真的很基础也重要

  • 相关阅读:
    搬家来博客园了
    公司初印象
    毕业之殇觉醒
    毕业之殇天意弄人
    毕业之殇预告篇
    scribe 安装文档
    毕业之殇寻找
    IOS 资料整理(转)
    IOS IPHONE相册应用 资料整理
    NSFileManager和NSFileHandle(附:获取文件大小 )
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9007697.html
Copyright © 2020-2023  润新知