线段树(乘法lazy+加法lazy+区间)

发布于:2023-01-18 ⋅ 阅读:(532) ⋅ 点赞:(0)
#include<bits/stdc++.h>
using namespace std;
#define int  long long
const int N=1e5+500;
#define inf 0x3f3f3f3f3f
#define PII pair<int,int>
int mod;
struct node
{
    int l,r;
    int val;
    int lazyP;
    int lazyM;
}tree[N<<2];
int s[N];
int n,m;
void push_up(int now)
{
    tree[now].val=(tree[now<<1].val+tree[now<<1|1].val)%mod;
}
//lazy操作
void push_down(int now)
{
         //先乘后加不会出错
        //更新乘法值
        tree[now<<1].val=(tree[now<<1].val*tree[now].lazyM)%mod;
        tree[now<<1|1].val=(tree[now<<1|1].val*tree[now].lazyM)%mod;
         //更新乘法lazy
        tree[now<<1].lazyM=(tree[now].lazyM*tree[now<<1].lazyM)%mod;
        tree[now<<1|1].lazyM=(tree[now].lazyM*tree[now<<1|1].lazyM)%mod;
         //更新加法值(区间*lazy)
        tree[now<<1].val=((tree[now<<1].r-tree[now<<1].l+1)*tree[now].lazyP+tree[now<<1].val)%mod;
        tree[now<<1|1].val=((tree[now<<1|1].r-tree[now<<1|1].l+1)*tree[now].lazyP+tree[now<<1|1].val)%mod;
        //  更新加法lazy,乘上乘法lazy  
        tree[now<<1].lazyP=(tree[now].lazyP+tree[now<<1].lazyP*tree[now].lazyM)%mod;
        tree[now<<1|1].lazyP=(tree[now].lazyP+tree[now<<1|1].lazyP*tree[now].lazyM)%mod;
        
        tree[now].lazyP=0;tree[now].lazyM=1;

}

void build(int now,int l,int r)
{
    tree[now].l=l;
    tree[now].r=r;
    tree[now].lazyM=1;
    tree[now].lazyP=0;
    if(l==r)
    {   s[l]%=mod;
        tree[now].val=s[l];

        return;
    }
    int mid=(l+r)/2;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    push_up(now);
}
void update_mul(int now,int l,int r,int val)
{
    if(l<=tree[now].l&&tree[now].r<=r)
    {
        tree[now].val=(val*tree[now].val)%mod;
        tree[now].lazyM=(tree[now].lazyM*val)%mod;
        tree[now].lazyP=(tree[now].lazyP*val)%mod;
        return;
    }
    push_down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(l<=mid)
    {
        update_mul(now<<1,l,r,val);
    }
    if(mid<r)
    {
        update_mul(now<<1|1,l,r,val);
    }
    push_up(now);
}
void update_plus(int now,int l,int r,int val)
{
    if(l<=tree[now].l&& tree[now].r<=r)
    {
        tree[now].val=(tree[now].val+(tree[now].r-tree[now].l+1)*val)%mod;
        tree[now].lazyP=(tree[now].lazyP+val)%mod;
        return;
    }
    push_down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(l<=mid)
    {
        update_plus(now<<1,l,r,val);
    }
    if(r>mid)
    {
        update_plus(now<<1|1,l,r,val);
    }
    push_up(now);
}
int query(int now,int l,int r)
{
    if(l<=tree[now].l&&tree[now].r<=r)
    {
        return tree[now].val;
    }
    push_down(now);
    int res=0;
    int mid=(tree[now].l+tree[now].r)/2;
    if(l<=mid)
    {
        res=(res+ query(now<<1,l,r))%mod;
    }
    if(r>mid)
    {
        res=(res+ query(now<<1|1,l,r))%mod;
    }
    return res%mod;
}
void solve()
{
    cin>>n>>m>>mod;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
    }
    build(1,1,n);
    while(m--)
    {
        int op;
        cin>>op;
        int x,y,k;
        if(op==1)
        {
            cin>>x>>y>>k;
            update_mul(1,x,y,k);
        }
        else if(op==2)
        {
            cin>>x>>y>>k;
            update_plus(1,x,y,k);
        }
        else
        {
            cin>>x>>y;
            cout<<query(1,x,y)<<endl;
        }
    }

}
signed main()
{
//    int t;cin>>t;while(t--)
    solve();
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到