Transformation HDU - 4578(区间混合标记)

本文详细解析了一种复杂的数据结构——区间操作树状数组,用于高效处理区间加、乘、覆盖等操作,并通过实例代码展示了如何维护加法、乘法和覆盖标记,以及在标记下传时的注意事项。文章强调了操作顺序的重要性,即先计算三次幂,再计算二次幂,最后计算一次幂。

题意:区间加,区间乘,区间覆盖,区间一,二,三次幂和。

维护三个标记,乘法的,加法的,覆盖的。
考虑三种操作的到来时间。
如果该次操作为覆盖的话,前两种标记应该直接失效
如果该次为乘法的话,那么应该给加法标记也乘上这个值,这样才能使(x+b)a -> ax+b*a,在标记下传时变得可维护。
如果为加法的话就直接加。
标记下传的时候注意如果有覆盖标记,那么左右子树的乘法及加法失效。
加法标记需要先乘上乘法标记再加上加法标记。
然后需要注意的就是一定要先算三次幂,再算二次幂,再算一次幂,这个纸上画一画展开一下式子就懂了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=1e5+7;
ll sum[maxn<<2|1][4];
ll add[maxn<<2|1],mutil[maxn<<2|1],cover[maxn<<2|1];
const int mod=10007;
void pushup(int k){
    for(int i=1;i<=3;++i) sum[k][i]=(sum[k<<1][i]+sum[k<<1|1][i])%mod;
}

void pushdown(int l,int r,int k){
    int mid=(l+r)>>1;
    if(cover[k]){
        cover[k<<1]=cover[k<<1|1]=cover[k];
        add[k<<1]=add[k<<1|1]=0;
        mutil[k<<1]=mutil[k<<1|1]=1;
        ll x=cover[k];
        for(int i=1;i<=3;++i){
            sum[k<<1][i]=(mid-l+1)*x%mod;
            sum[k<<1|1][i]=(r-mid)*x%mod;
            x=x*cover[k]%mod;
        }
        cover[k]=0;
    }
    if(add[k]||mutil[k]!=1){
        (add[k<<1]*=mutil[k])%=mod;
        (add[k<<1|1]*=mutil[k])%=mod;
        (add[k<<1]+=add[k])%=mod;
        (add[k<<1|1]+=add[k])%=mod;
        (mutil[k<<1]*=mutil[k])%=mod;
        (mutil[k<<1|1]*=mutil[k])%=mod;

        (sum[k<<1][3]*=mutil[k]*mutil[k]*mutil[k])%=mod;
        (sum[k<<1|1][3]*=mutil[k]*mutil[k]*mutil[k])%=mod;
        (sum[k<<1][3]+=3*mutil[k]*mutil[k]*add[k]*sum[k<<1][2])%=mod;
        (sum[k<<1|1][3]+=3*mutil[k]*mutil[k]*add[k]*sum[k<<1|1][2])%=mod;
        (sum[k<<1][3]+=3*mutil[k]*add[k]*add[k]*sum[k<<1][1])%=mod;
        (sum[k<<1|1][3]+=3*mutil[k]*add[k]*add[k]*sum[k<<1|1][1])%=mod;
        (sum[k<<1][3]+=(mid-l+1)*add[k]*add[k]*add[k])%=mod;
        (sum[k<<1|1][3]+=(r-mid)*add[k]*add[k]*add[k])%=mod;


        (sum[k<<1][2]*=mutil[k]*mutil[k])%=mod;
        (sum[k<<1|1][2]*=mutil[k]*mutil[k])%=mod;
        (sum[k<<1][2]+=(mid-l+1)*add[k]*add[k])%=mod;
        (sum[k<<1|1][2]+=(r-mid)*add[k]*add[k])%=mod;
        (sum[k<<1][2]+=2*mutil[k]*add[k]*sum[k<<1][1])%=mod;
        (sum[k<<1|1][2]+=2*mutil[k]*add[k]*sum[k<<1|1][1])%=mod;

        (sum[k<<1][1]*=mutil[k])%=mod;
        (sum[k<<1|1][1]*=mutil[k])%=mod;
        (sum[k<<1][1]+=(mid-l+1)*add[k])%=mod;
        (sum[k<<1|1][1]+=(r-mid)*add[k])%=mod;

        mutil[k]=1,add[k]=0;
    }
}

void build(int l,int r,int k){
    for(int i=1;i<=3;++i) sum[k][i]=0;
    add[k]=0,mutil[k]=1,cover[k]=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
}

//1 add 2 mutil 3 cover
void updata(int l,int r,int k,int L,int R,int type,ll val){
    if(l>=L&&r<=R){
        if(type==1){
            (add[k]+=val)%=mod;

            (sum[k][3]+=3*val*val*sum[k][1])%=mod;
            (sum[k][3]+=3*val*sum[k][2])%=mod;
            (sum[k][3]+=(r-l+1)*val*val*val)%=mod;

            (sum[k][2]+=(r-l+1)*val*val)%=mod;
            (sum[k][2]+=2*val*sum[k][1])%=mod;

            (sum[k][1]+=(r-l+1)*val)%=mod;
        }
        else if(type==2){
            (add[k]*=val)%=mod;
            (mutil[k]*=val)%=mod;
            ll x=val;
            for(int i=1;i<=3;++i){
                (sum[k][i]*=x)%=mod;
                (x*=val)%=mod;
            }
        }
        else{
            cover[k]=val;
            add[k]=0;
            mutil[k]=1;
            sum[k][1]=val*(r-l+1)%mod;
            sum[k][2]=val*val*(r-l+1)%mod;
            sum[k][3]=val*val*val*(r-l+1)%mod;
        }

        return ;
    }
    int mid=(l+r)>>1;
    pushdown(l,r,k);
    if(L<=mid) updata(l,mid,k<<1,L,R,type,val);
    if(R>mid) updata(mid+1,r,k<<1|1,L,R,type,val);
    pushup(k);
}

ll myfind(int l,int r,int k,int L,int R,int pos){
    if(l>=L&&r<=R) return sum[k][pos];
    pushdown(l,r,k);
    int mid=(l+r)>>1;
    ll res=0;
    if(L<=mid) (res+=myfind(l,mid,k<<1,L,R,pos))%=mod;
    if(R>mid) (res+=myfind(mid+1,r,k<<1|1,L,R,pos))%=mod;
    return res;
}

int main(){
    int n,m,id,l,r,val;
    while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
        build(1,n,1);
        while(m--){
            scanf("%d%d%d%d",&id,&l,&r,&val);
            if(id==4) printf("%lld\n",myfind(1,n,1,l,r,val));
            else updata(1,n,1,l,r,id,val);
        }

    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值