题意:区间加,区间乘,区间覆盖,区间一,二,三次幂和。
维护三个标记,乘法的,加法的,覆盖的。
考虑三种操作的到来时间。
如果该次操作为覆盖的话,前两种标记应该直接失效
如果该次为乘法的话,那么应该给加法标记也乘上这个值,这样才能使(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;
}
本文详细解析了一种复杂的数据结构——区间操作树状数组,用于高效处理区间加、乘、覆盖等操作,并通过实例代码展示了如何维护加法、乘法和覆盖标记,以及在标记下传时的注意事项。文章强调了操作顺序的重要性,即先计算三次幂,再计算二次幂,最后计算一次幂。
1213

被折叠的 条评论
为什么被折叠?



