【题解】洛谷P2023[AHOI2009]维护序列 线段树

题目

题目链接

#include<cstdio>
#define lc o<<1
#define rc o<<1|1
typedef long long ll;
const int N=1e5+10;
int n,m;
ll p;
ll a[N],sum[N<<2],add[N<<2],mul[N<<2];
void build(int o,int l,int r)
{
    add[o]=0;mul[o]=1;
    if(l==r)
    {
        sum[o]=a[l]%p;
        return;
    }
    int mid=l+r>>1;
    build(lc,l,mid);build(rc,mid+1,r);
    sum[o]=(sum[lc]+sum[rc])%p;
}
void push_down(int o,int l,int r)
{
    if(mul[o]!=1)
    {
        sum[lc]=sum[lc]*mul[o]%p;
        sum[rc]=sum[rc]*mul[o]%p;
        mul[lc]=mul[lc]*mul[o]%p;
        mul[rc]=mul[rc]*mul[o]%p;
        add[lc]=add[lc]*mul[o]%p;
        add[rc]=add[rc]*mul[o]%p;
        mul[o]=1;
    }
    int mid=l+r>>1;
    if(add[o])
    {
        sum[lc]=(sum[lc]+add[o]*(mid-l+1))%p;
        sum[rc]=(sum[rc]+add[o]*(r-mid))%p;
        add[lc]=(add[lc]+add[o])%p;
        add[rc]=(add[rc]+add[o])%p;
        add[o]=0;
    }
}
void upmul(int o,int l,int r,int nl,int nr,ll c)
{
    if(nl<=l&&r<=nr)
    {
        sum[o]=sum[o]*c%p;
        mul[o]=mul[o]*c%p;
        add[o]=add[o]*c%p;
        return;
    }
    push_down(o,l,r);
    int mid=l+r>>1;
    if(nl<=mid)upmul(lc,l,mid,nl,nr,c);
    if(nr>mid)upmul(rc,mid+1,r,nl,nr,c);
    sum[o]=(sum[lc]+sum[rc])%p;
}
void upadd(int o,int l,int r,int nl,int nr,ll c)
{
    if(nl<=l&&r<=nr)
    {
        sum[o]=(sum[o]+(r-l+1)*c)%p;
        add[o]=(add[o]+c)%p;
        return;
    }
    push_down(o,l,r);
    int mid=l+r>>1;
    if(nl<=mid)upadd(lc,l,mid,nl,nr,c);
    if(nr>mid)upadd(rc,mid+1,r,nl,nr,c);
    sum[o]=(sum[lc]+sum[rc])%p;
}
ll query(int o,int l,int r,int nl,int nr)
{
    if(nl<=l&&r<=nr)return sum[o]%p;
    push_down(o,l,r);
    int mid=l+r>>1;
    ll ans=0;
    if(nl<=mid)ans=(ans+query(lc,l,mid,nl,nr))%p;
    if(nr>mid)ans=(ans+query(rc,mid+1,r,nl,nr))%p;
    return ans%p;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%lld",&n,&p);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    build(1,1,n);
    scanf("%d",&m);
    int op,t,g;
    ll c;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&t,&g);
        if(op==1)scanf("%lld",&c),upmul(1,1,n,t,g,c);
        else if(op==2)scanf("%lld",&c),upadd(1,1,n,t,g,c);
        else printf("%lld\n",query(1,1,n,t,g));
    }
    return 0;
}

总结

裸的线段树区间增乘模板题。

猜你喜欢

转载自blog.csdn.net/qq_41958841/article/details/82390887
今日推荐