zoukankan      html  css  js  c++  java
  • 洛谷 P3373 【模板】线段树 2

    题意

    维护一段序列,支持区间乘,区间加,区间求和。

    注意到操作有两种,则维护两个(lazytag),分别对应乘和加。

    区间加

    与模板1相同。

    区间乘

    除了更新乘标记,将要加上的部分也要受乘法影响。所以要把两个标记都乘一次。

    标记下传

    首先乘标记可以直接下传。

    而子节点的加标记还没有做乘法,而当前节点已经做了。所以要将子节点乘完在加上当前节点的加标记。

    在上述两次标记更新后,分别将子节点的值也更新,就完成了。

    代码

    #include<iostream>
    #define int long long
    using namespace std;
    const int maxn=100005;
    int p,n,m,a[maxn],seg[maxn<<2],tag1[maxn<<2],tag2[maxn<<2];
    int u,v,w;
    
    inline void upd(int x)
    {
        seg[x]=(seg[x<<1]+seg[x<<1|1])%p;
    }
    
    inline void build(int x,int l,int r)
    {
        int mid=(l+r)>>1;
        if(l==r)
        {
            seg[x]=a[l]%p;
            return;
        }
        tag2[x]=1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        upd(x);
    }
    
    inline int push_down1(int x,int l,int r)
    {
        tag1[x<<1]=(tag1[x<<1]*tag2[x]+tag1[x])%p;
    	tag1[x<<1|1]=(tag1[x<<1|1]*tag2[x]+tag1[x])%p;
        int mid=(l+r)>>1;
        seg[x<<1]=(seg[x<<1]+(mid-l+1)*tag1[x])%p;
        seg[x<<1|1]=(seg[x<<1|1]+(r-mid)*tag1[x])%p;
        tag1[x]=0;
    	tag2[x]=1;
    }
    
    inline int push_down2(int x,int l,int r)
    {
        tag2[x<<1]=(tag2[x<<1]*tag2[x])%p;
    	tag2[x<<1|1]=(tag2[x<<1|1]*tag2[x])%p;
        seg[x<<1]=(seg[x<<1]*tag2[x])%p;
        seg[x<<1|1]=(seg[x<<1|1]*tag2[x])%p;
        //tag1[x]*=tag2[x];
    }
    
    inline int query(int x,int l,int r,int ql,int qr)
    {
        int temp=0,mid=(l+r)>>1;
        if(ql<=l&&r<=qr) return seg[x];
        push_down2(x,l,r);
        push_down1(x,l,r);
        if(ql<=mid) temp=(temp+query(x<<1,l,mid,ql,qr))%p;
        if(mid<qr) temp=(temp+query(x<<1|1,mid+1,r,ql,qr))%p;
        return temp;
    }
    
    inline void modify1(int x,int l,int r,int ql,int qr,int num)
    {
        if(ql<=l&&r<=qr)
        {
            seg[x]=(seg[x]+(r-l+1)*num)%p;
            tag1[x]=(tag1[x]+num)%p;
        } else {
            push_down2(x,l,r);
            push_down1(x,l,r);
            int mid=(l+r)>>1;
            if(ql<=mid) modify1(x<<1,l,mid,ql,qr,num);
            if(mid<qr) modify1(x<<1|1,mid+1,r,ql,qr,num);
            upd(x);
        }
    }
    
    inline void modify2(int x,int l,int r,int ql,int qr,int num)
    {
        if(ql<=l&&r<=qr)
        {
            seg[x]=(seg[x]*num)%p;
            tag2[x]=(tag2[x]*num)%p;
            tag1[x]=(tag1[x]*num)%p;
        } else {
            push_down2(x,l,r);
            push_down1(x,l,r);
            int mid=(l+r)>>1;
            if(ql<=mid) modify2(x<<1,l,mid,ql,qr,num);
            if(mid<qr) modify2(x<<1|1,mid+1,r,ql,qr,num);
            upd(x);
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin>>n>>m>>p;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        build(1,1,n);
        for(register int i=1;i<=m;i++)
        {
            cin>>u>>v>>w;
            if(u==3)
                cout<<query(1,1,n,v,w)<<"
    ";
            else
            if(u==1)
            {
                cin>>u;
    			modify2(1,1,n,v,w,u);
    		}else
            if(u==2)
            {
                cin>>u;
    			modify1(1,1,n,v,w,u);
    		}
        }
        return 0;
    }
    
  • 相关阅读:
    Golang 用go-sql-driver 调用MySQL存储过程时的问题排查
    mysqlbinlog 查看binlog时报错unknown variable 'default-character-set=utf8'
    HBase Go客户端Row构造注意事项
    MySQL JOIN操作报错问题小解
    MySQL主从同步的一个小问题解决
    PHP 多个mysql连接的问题
    记一起动态库加载错误问题排查过程
    DNS缓存
    C输出大于127的ACSII字符
    Mint17 一些安装备忘
  • 原文地址:https://www.cnblogs.com/ehznehc/p/11296883.html
Copyright © 2011-2022 走看看