题意:
对区间内的数进行各种操作。
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
#include
#include
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;
}
下传标记应该有更高效的方法的。有空再研究。。。