P2023 [AHOI2009]维护序列 · 线段树

题解

吐血
线段树有了懒标记,不管写多少次都那么要命

添加两个懒标记:add 和 mul
对于每个区间来说都有以下公式:区间的值 = ( 区间和 + 新加的数 ) * 新乘的数

详细见代码


在这里插入图片描述


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N=1e6+10;
int n,m,k,p;
ll a[N];
ll sum[N<<2];
ll add[N<<2],mul[N<<2];//懒标记

void pushup(int rt){
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
}

void pushdown(int rt,int len){//(sum+add)*mul
    //更新左儿子 左儿子区间长度为len+1>>1
    sum[rt<<1]=(sum[rt<<1]*mul[rt]+add[rt]*(len+1>>1))%p;
    mul[rt<<1]=(mul[rt<<1]*mul[rt])%p;
    add[rt<<1]=(add[rt<<1]*mul[rt]+add[rt])%p;
    //更新右儿子 右儿子区间长度为len>>1
    sum[rt<<1|1]=(sum[rt<<1|1]*mul[rt]+add[rt]*(len>>1))%p;
    mul[rt<<1|1]=(mul[rt<<1|1]*mul[rt])%p;
    add[rt<<1|1]=(add[rt<<1|1]*mul[rt]+add[rt])%p;
    //更新父亲
    mul[rt]=1;
    add[rt]=0;
}

void build(int l,int r,int rt){
    mul[rt]=1;
    if(l==r){
        cin>>sum[rt];//叶节点即 sum[rt]=a[l]
        return ;
    }
    int mid=l+r>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void Add(int x,int y,ll val,int l,int r,int rt){
    if(x<=l && r<=y){
        add[rt]=(add[rt]+val)%p;//标记一下增加的数
        sum[rt]=(sum[rt]+val*(r-l+1))%p;
        return;
    }
    pushdown(rt,r-l+1);
    int mid=l+r>>1;
    if(x<=mid)Add(x,y,val,lson);
    if(y>mid)Add(x,y,val,rson);
    pushup(rt);
}

void Multiple(int x,int y,ll val,int l,int r,int rt){
    if(x<=l && r<=y){
        mul[rt]=(mul[rt]*val)%p;
        sum[rt]=(sum[rt]*val)%p;
        add[rt]=(add[rt]*val)%p;// (sum+add)*mul
        return ;
    }
    pushdown(rt,r-l+1);
    int mid=l+r>>1;
    if(x<=mid)Multiple(x,y,val,lson);
    if(y>mid)Multiple(x,y,val,rson);
    pushup(rt);
}

ll query(int x,int y,int l,int r,int rt){
    if(x<=l && r<=y){
        return sum[rt];
    }
    pushdown(rt,r-l+1);
    int mid=l+r>>1;
    ll res=0;
    if(x<=mid)res+=query(x,y,lson);
    if(y>mid)res+=query(x,y,rson);
    pushup(rt);
    return (res%p);
}

int main(){
    cin>>n>>p;
    build(1,n,1);
    cin>>m;
    for (int i = 1,op,x,y,z; i <= m; ++i) {
        cin>>op>>x>>y;
        if(op==1){
            cin>>z;
            Multiple(x,y,z,1,n,1);
        }else if(op==2){
            cin>>z;
            Add(x,y,z,1,n,1);
        }else{
            cout <<query(x,y,1,n,1) << endl;
        }
    }
    return 0;
}
发布了34 篇原创文章 · 获赞 0 · 访问量 964

猜你喜欢

转载自blog.csdn.net/Yubing792289314/article/details/104160041
今日推荐