[线段树] (g) hdu4578 线段树维护区间幂次和(好题)
大意: 长度为n的序列初始全为0,m个操作,有多组数据
操作有:1. 区间加k
2. 区间乘k
3. 区间内全改为k
4. 求区间内每个数的k次幂和(1<=k<=3)
解析:
- 区间乘自行跳转luogu3373,tag最好先乘后加(分别是操作1、2)
- 第三个tag维护操作3,可以发现,一旦被区间推平(指成为同一个数的重复),那么已存的 加乘tag 都没有意义了 ,所以新建第三个tag,维护操作3,优先级 大于乘法大于加法 , 且pushdown时消除其它标记 .
- 对于询问4,十分少见,使得我看到这题时直接想到用珂朵莉树来做...但其实只需要用val[][4]即可维护而不用暴力求和,val[root][p]表示节点root下的p次幂和,推导过程如下:...
01=02=03=0
若该节点维护的权值为: val[1]=a1+a2+....+an,在操作1中加的数为k
val[1](new)=val[1]+(r-l+1)*k //详见加法tag
有(a+b)2=a2+b2+2bk
原val[2]=[ a12 + a22 +...+ an2]
有val[2](new)=[ (a1+k)2 + (a2+k)2 +...+ (an+k)2]
=( a12+a22+...+an2 ) + 2k(a1+a2+....+an) + n*k2
=val[2] + (r-l+1)*k2 + 2k*val[1](原,此处可看出2的优先级高于1)
同理
∵(a+b)3=a3+b3+3a2b+3ab2
∴val[3]=val[3] + 3k∗val[2]+3k2∗val[1] + (r−l+1)∗k3
显然3的优先级又高于2
总结:
3>2>1(不管是操作的tag还是val...qwq好巧啊)
注意细节:
1. 多组数据,因为不能覆盖上一组,所以需要清空(build)
2. 操作注意优先级
3. 处处取模避免爆int
4. 操作复杂,代码量大,不要敲错,很难查错
5. 尤其注意pushdown部分的检查
6. 线段树4倍空间
7. 一起%scPointer
Code
/*hdu 4578 by lsy263*/ #include<iostream> #include<algorithm> #include<cstdio> #include<cctype> #include<ctime> using namespace std;const int N=1e6+3,scPointer=10007,INF=0x7fffffff; int v[N<<2][4],pt[N<<2],mt[N<<2],Assign[N<<2],n,m; //For segment-tree #define LS (rt<<1) #define RS (LS|1) #define pushup(rt)\ (v[rt][1]=v[LS][1]+v[RS][1])%=scPointer;\ (v[rt][2]=v[LS][2]+v[RS][2])%=scPointer;\ (v[rt][3]=v[LS][3]+v[RS][3])%=scPointer; inline int squ(int a,int b){ //没有必要快速幂..但是写个函数便于阅读 int base =a; while(--b)(base*=a)%=scPointer; int base=1; return base; } void build(int rt,int l,int r){ pt[rt]=0;mt[rt]=1;Assign[rt]=-INF; v[rt][1]=v[rt][2]=v[rt][3]=0; if(l==r)return; int mid=l+r>>1; build(LS,l,mid); build(RS,mid+1,r); return ; } inline void pushdown(int rt,int l,int r){ int mid=l+r>>1; if(Assign[rt]!=-INF){ //会覆盖下面所有标记(3pts) Assign[LS]=Assign[RS]=Assign[rt]; ////// ------------- v v[LS][1]=(mid-l+1)*Assign[rt]%scPointer; v[RS][1]=(r-mid)*Assign[rt]%scPointer; v[LS][2]=(mid-l+1)*squ(Assign[rt],2)%scPointer; v[RS][2]=(r-mid)*squ(Assign[rt],2)%scPointer; v[LS][3]=(mid-l+1)*squ(Assign[rt],3)%scPointer; v[RS][3]=(r-mid)*squ(Assign[rt],3)%scPointer; ///// -------------- mt[LS]=1,pt[LS]=0; mt[RS]=1,pt[RS]=0; Assign[rt]=-INF; //return; } if(mt[rt]!=1){ ///// -------------- Tag (pt[LS]*=mt[rt])%=scPointer; (pt[RS]*=mt[rt])%=scPointer; (mt[LS]*=mt[rt])%=scPointer; (mt[RS]*=mt[rt])%=scPointer; ///// -------------- v (v[LS][1]*=mt[rt])%=scPointer; (v[RS][1]*=mt[rt])%=scPointer; (v[LS][2]*=squ(mt[rt],2))%=scPointer; (v[RS][2]*=squ(mt[rt],2))%=scPointer; (v[LS][3]*=squ(mt[rt],3))%=scPointer; (v[RS][3]*=squ(mt[rt],3))%=scPointer; ///// -------------- mt[rt]=1; } if(pt[rt]){ ///// -------------- Tag (pt[LS]+=pt[rt])%=scPointer; (pt[RS]+=pt[rt])%=scPointer; ///// -------------- v (v[LS][3]+=3*v[LS][2]*pt[rt]%scPointer+3*squ(pt[rt],2)*v[LS][1]%scPointer+(mid-l+1)*squ(pt[rt],3)%scPointer)%=scPointer; (v[RS][3]+=3*v[RS][2]*pt[rt]%scPointer+3*squ(pt[rt],2)*v[RS][1]%scPointer+(r-mid)*squ(pt[rt],3)%scPointer)%=scPointer; (v[LS][2]+=2*pt[rt]*v[LS][1]%scPointer+(mid-l+1)*squ(pt[rt],2)%scPointer)%=scPointer; (v[RS][2]+=2*pt[rt]*v[RS][1]%scPointer+(r-mid)*squ(pt[rt],2)%scPointer)%=scPointer; (v[LS][1]+=(mid-l+1)*pt[rt])%=scPointer; (v[RS][1]+=(r-mid)*pt[rt])%=scPointer; ///// -------------- /* v[3]+=3kv[2]+3v[1]k^2+len*k^3 v[2]+=2kv[1]+len*k^2 v[1]+=len*k */ pt[rt]=0; }return; } inline void update(int rt,int l,int r,int x,int y,int k,int ty){ //Update if(l>=x&&r<=y){ //推平要清空tag switch(ty){ case 1: //Plus (pt[rt]+=k)%=scPointer; (v[rt][3]+=3*v[rt][2]*k%scPointer+3*squ(k,2)*v[rt][1]%scPointer+(r-l+1)*squ(k,3))%=scPointer; (v[rt][2]+=2*k*v[rt][1]+(r-l+1)*squ(k,2))%=scPointer; (v[rt][1]+=(r-l+1)*k)%=scPointer; /* v[3]+=3kv[2]+3v[1]k^2+len*k^3 v[2]+=2kv[1]+len*k^2 v[1]+=len*k */ break; case 2: //Mul (pt[rt]*=k)%=scPointer; (mt[rt]*=k)%=scPointer; (v[rt][1]*=k)%=scPointer; (v[rt][2]*=squ(k,2))%=scPointer; (v[rt][3]*=squ(k,3))%=scPointer; break; default: //Assign Assign[rt]=k;mt[rt]=1;pt[rt]=0; v[rt][1]=(r-l+1)*k%scPointer; v[rt][2]=(r-l+1)*squ(k,2)%scPointer; v[rt][3]=(r-l+1)*squ(k,3)%scPointer; } return; }pushdown(rt,l,r); int mid=l+r>>1; if(x<=mid)update(LS,l,mid,x,y,k,ty); if(y>mid)update(RS,mid+1,r,x,y,k,ty); pushup(rt); return; } int query(int rt,int l,int r,int x,int y,int p){ if(l>=x&&r<=y) return v[rt][p]%scPointer; pushdown(rt,l,r); int mid=l+r>>1,res=0; if(x<=mid)(res+=query(LS,l,mid,x,y,p))%=scPointer; if(y>mid)(res+=query(RS,mid+1,r,x,y,p))%=scPointer; return res; } int main(){int tp,x,y,k; while(scanf("%d%d",&n,&m)!=EOF&&n&&m){ build(1,1,n); while(m --){ scanf("%d%d%d%d",&tp,&x,&y,&k); if(tp==4) printf("%d\n",query(1,1,n,x,y,k)%scPointer); else update(1,1,n,x,y,k%scPointer,tp); } } return 0; }