5 5 3 3 5 7 1 2 4 4 4 1 5 2 2 2 5 8 4 3 5 3 0 0
307 7489
题意:
对区间内的数进行各种操作。
1,把[x,y]区间上的每个数加上c。
2,把[x,y]区间上的每个数乘上c.
3,把[x,y]区间上的数置成c。
4,询问区间[x,y]上的每个数的p次方的和。
思路:
一看就是线段树。开始被次方和吓到了。以前从来没遇到这种类型的。但是再看p的范围只有1到3。于是想到了每个结点维护三个和即sum[0],sum[1],sum[2]分别表示区间内数1次方2次方3次方的和。但是怎么更新结点这几个值呢?
想到线段树都是从儿子结点获得信息然后跟新父亲结点信息的。考虑对一个区间内的数加上一个数c后对这三个值有什么影响。首先考虑一个数c的情况。一次方就不说了直接加上c*区间长度len就行了。
二次方。一个数开始为a。后来为a+c。则平方后为a*a+2*a*c+c*c。比原来多了2*a*c+c*c。而对于整个区间增加
2*sum[0]*c+len*c*c。三次方增加3*sum[1]*c+3*sum[0]*c*c+len*c*c*c。
根据题目的操作在每个结点加三个标记。
same[k]表示区间内数值是否一样。如果相同在用一个变量value[k]存该值。
addv[k]表示区间内的数加的值。
mul[k]表示区间内的数乘的值。
但是想到这里又卡住了。因为在addv[k]和mul[k]是冲突的。因为当这两个标记时不知道是先加的还是先乘的。于是想到标记递归往下传知道不冲突或到了叶子结点停止。比赛时没敢写。觉得这样可能更新到叶子结点效率太低,结果下来一写2sA了。
只是要注意到取模的问题。因为算次方很容易超的。
详细见代码:
#include <iostream> #include<string.h> #include<stdio.h> using namespace std; const int maxn=100010,mod=10007; int addv[maxn<<2],mul[maxn<<2],value[maxn<<2],sum[maxn<<2][3]; bool same[maxn<<2]; int n,m; void small(int k)//对各sum取模 { int i; for(i=0;i<3;i++) if(sum[k][i]>=mod) sum[k][i]%=mod; } void btree(int L,int R,int k)//建树 { int ls,rs,mid; addv[k]=0; mul[k]=1; same[k]=true; value[k]=0; sum[k][0]=sum[k][1]=sum[k][2]=0; if(L==R) return; ls=k<<1; rs=k<<1|1; mid=(L+R)>>1; btree(L,mid,ls); btree(mid+1,R,rs); } void pushdown(int L,int R,int k)//根据是否互斥下传标记 { int ls,rs,mid,lenl,lenr; ls=k<<1; rs=k<<1|1; mid=(L+R)>>1; lenl=mid-L+1; lenr=R-mid; if(same[k]) { same[ls]=same[rs]=true; value[ls]=value[rs]=value[k]%mod; sum[ls][0]=value[ls]*lenl%mod; sum[ls][1]=sum[ls][0]*value[ls]%mod; sum[ls][2]=sum[ls][1]*value[ls]%mod; sum[rs][0]=value[rs]*lenr%mod; sum[rs][1]=sum[rs][0]*value[rs]%mod; sum[rs][2]=sum[rs][1]*value[rs]%mod; small(ls); small(rs); addv[ls]=addv[rs]=0; mul[ls]=mul[rs]=1; same[k]=false; } if(addv[k]!=0) { if(same[ls]) { value[ls]+=addv[k]%mod; value[ls]%=mod; sum[ls][0]=value[ls]*lenl%mod; sum[ls][1]=sum[ls][0]*value[ls]%mod; sum[ls][2]=sum[ls][1]*value[ls]%mod; small(ls); } else if(mul[ls]!=1) { pushdown(L,mid,ls); mul[ls]=1; addv[ls]=addv[k]%mod; sum[ls][2]+=3*sum[ls][1]%mod*addv[k]%mod+3*sum[ls][0]%mod*addv[k]%mod*addv[k]%mod+lenl%mod*addv[k]%mod*addv[k]%mod*addv[k]%mod; sum[ls][1]+=lenl%mod*addv[k]%mod*addv[k]%mod+2*sum[ls][0]%mod*addv[k]%mod; sum[ls][0]+=lenl%mod*addv[k]%mod; small(ls); } else { addv[ls]+=addv[k]%mod; addv[ls]%=mod; sum[ls][2]+=3*sum[ls][1]%mod*addv[k]%mod+3*sum[ls][0]%mod*addv[k]%mod*addv[k]%mod+lenl%mod*addv[k]%mod*addv[k]%mod*addv[k]%mod; sum[ls][1]+=lenl%mod*addv[k]%mod*addv[k]%mod+2*sum[ls][0]%mod*addv[k]%mod; sum[ls][0]+=lenl%mod*addv[k]%mod; small(ls); } if(same[rs]) { value[rs]+=addv[k]%mod; value[rs]%=mod; sum[rs][0]=value[rs]*lenr%mod; sum[rs][1]=sum[rs][0]*value[rs]%mod; sum[rs][2]=sum[rs][1]*value[rs]%mod; small(rs); } else if(mul[rs]!=1) { pushdown(mid+1,R,rs); mul[rs]=1; addv[rs]=addv[k]%mod; sum[rs][2]+=3*sum[rs][1]%mod*addv[k]%mod+3*sum[rs][0]%mod*addv[k]%mod*addv[k]%mod+lenr%mod*addv[k]%mod*addv[k]%mod*addv[k]%mod; sum[rs][1]+=lenr%mod*addv[k]%mod*addv[k]%mod+2*sum[rs][0]%mod*addv[k]%mod; sum[rs][0]+=lenr*addv[k]%mod; small(rs); } else { addv[rs]+=addv[k]%mod; addv[rs]%=mod; sum[rs][2]+=3*sum[rs][1]%mod*addv[k]%mod+3*sum[rs][0]%mod*addv[k]%mod*addv[k]%mod+lenr%mod*addv[k]%mod*addv[k]%mod*addv[k]%mod; sum[rs][1]+=lenr%mod*addv[k]%mod*addv[k]%mod+2*sum[rs][0]%mod*addv[k]%mod; sum[rs][0]+=lenr*addv[k]%mod; small(rs); } addv[k]=0; } else if(mul[k]!=1) { if(same[ls]) { value[ls]*=mul[k]%mod; value[ls]%=mod; sum[ls][0]=lenl%mod*value[ls]%mod; sum[ls][1]=sum[ls][0]*value[ls]%mod; sum[ls][2]=sum[ls][1]*value[ls]%mod; small(ls); } else if(addv[ls]!=0) { pushdown(L,mid,ls); mul[ls]=mul[k]%mod; sum[ls][0]*=mul[k]%mod; sum[ls][1]*=mul[k]%mod*mul[k]%mod; sum[ls][2]*=mul[k]%mod*mul[k]%mod*mul[k]%mod; small(ls); } else { mul[ls]*=mul[k]%mod; mul[ls]%=mod; sum[ls][0]*=mul[k]%mod; sum[ls][1]*=mul[k]%mod*mul[k]%mod; sum[ls][2]*=mul[k]%mod*mul[k]%mod*mul[k]%mod; small(ls); } if(same[rs]) { value[rs]*=mul[k]%mod; value[rs]%=mod; sum[rs][0]=lenr%mod*value[rs]%mod; sum[rs][1]=sum[rs][0]*value[rs]%mod; sum[rs][2]=sum[rs][1]*value[rs]%mod; small(rs); } else if(addv[rs]!=0) { pushdown(mid+1,R,rs); mul[rs]=mul[k]%mod; sum[rs][0]*=mul[k]%mod; sum[rs][1]*=mul[k]%mod*mul[k]%mod; sum[rs][2]*=mul[k]%mod*mul[k]%mod*mul[k]%mod; small(rs); } else { mul[rs]*=mul[k]%mod; mul[rs]%=mod; sum[rs][0]*=mul[k]%mod; sum[rs][1]*=mul[k]%mod*mul[k]%mod; sum[rs][2]*=mul[k]%mod*mul[k]%mod*mul[k]%mod; small(rs); } mul[k]=1; } } void update(int L,int R,int l,int r,int k,int op,int c)//更新 { int ls,rs,mid,len; len=R-L+1; c%=mod; len%=mod; if(l==L&&r==R) { if(op==1) { if(same[k]) { value[k]+=c; value[k]%=mod; sum[k][0]=len*value[k]%mod; sum[k][1]=sum[k][0]*value[k]%mod; sum[k][2]=sum[k][1]*value[k]%mod; } else if(mul[k]!=1) { pushdown(L,R,k); addv[k]=c; sum[k][2]+=3*sum[k][1]%mod*c%mod+3*sum[k][0]%mod*c%mod*c%mod+len*c%mod*c%mod*c%mod; sum[k][1]+=len*c%mod*c%mod+2*sum[k][0]%mod*c%mod; sum[k][0]+=len*c%mod; } else { addv[k]+=c; addv[k]%=mod; sum[k][2]+=3*sum[k][1]%mod*c%mod+3*sum[k][0]%mod*c%mod*c%mod+len*c%mod*c%mod*c%mod; sum[k][1]+=len*c%mod*c%mod+2*sum[k][0]%mod*c%mod; sum[k][0]+=len*c%mod; } } else if(op==2) { if(same[k]) { value[k]*=c; value[k]%=mod; sum[k][0]=value[k]*len%mod; sum[k][1]=sum[k][0]*value[k]%mod; sum[k][2]=sum[k][1]*value[k]%mod; } else if(addv[k]!=0) { pushdown(L,R,k); mul[k]=c; sum[k][0]*=c; sum[k][1]*=c*c%mod; sum[k][2]*=c*c%mod*c%mod; } else { mul[k]*=c%mod; mul[k]%=mod; sum[k][0]*=c%mod; sum[k][1]*=c%mod*c%mod; sum[k][2]*=c%mod*c%mod*c%mod; } } else if(op==3) { same[k]=true; value[k]=c; addv[k]=0; mul[k]=1; sum[k][0]=len*c%mod; sum[k][1]=sum[k][0]*c%mod; sum[k][2]=sum[k][1]*c%mod; } small(k); return; } ls=k<<1; rs=k<<1|1; mid=(L+R)>>1; pushdown(L,R,k); if(l>mid) update(mid+1,R,l,r,rs,op,c); else if(r<=mid) update(L,mid,l,r,ls,op,c); else { update(L,mid,l,mid,ls,op,c); update(mid+1,R,mid+1,r,rs,op,c); } sum[k][0]=sum[ls][0]+sum[rs][0]; sum[k][1]=sum[ls][1]+sum[rs][1]; sum[k][2]=sum[ls][2]+sum[rs][2]; small(k); //printf("%d->%d %d %d %d\n",L,R,sum[k][0],sum[k][1],sum[k][2]); } int qu(int L,int R,int l,int r,int k,int p) { int ls,rs,mid; if(l==L&&r==R) return sum[k][p]; ls=k<<1; rs=k<<1|1; mid=(L+R)>>1; pushdown(L,R,k); if(l>mid) return qu(mid+1,R,l,r,rs,p); else if(r<=mid) return qu(L,mid,l,r,ls,p); else return (qu(L,mid,l,mid,ls,p)+qu(mid+1,R,mid+1,r,rs,p))%mod; } int main() { int com,i,x,y,c; while(scanf("%d%d",&n,&m),n||m) { btree(1,n,1); for(i=1; i<=m; i++) { scanf("%d%d%d%d",&com,&x,&y,&c); if(com!=4) update(1,n,x,y,1,com,c); else printf("%d\n",qu(1,n,x,y,1,c-1)); } } return 0; }
下传标记应该有更高效的方法的。有空再研究。。。