洛谷 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;
}
原文地址:https://www.cnblogs.com/ehznehc/p/11296883.html