题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578
题意:初始时给一个全为0的数列,有四种操作
(1)将x->y的数全部加上c;
(2)将x->y的数全部乘以c;
(3)将x->y的数全部赋值为c;
(4)查询x->y的每个数的p次方的和;
思路:这一题涉及到特别多的操作,但都是区间上的操作,所以可以想到线段树,但这一题我吗要打三个标记(lazy,lazyadd,lazymul,分别是区间替换,期间加和区间乘)再用三个数组(sum1,sum2,sum3分别表示1次方,2次方和3次方),还要用两个数组(L,R记录左右端点)之后,就是令人窒息的push_down函数的编写啦。
首先,我们有三个标记,所以我们要确定一个运算的优先级。毫无疑问,lazy标记一定是优先级最高的,其次,乘法的优先级高于加法。为什么呢?
假设我们现在有三个操作,
第一个是给x->y区间+3,
第二个是给区间x->y *4,
第三个是给区间x->y +5;
那总的式子应该是
∑
\sum_{}
∑(a+3)*4+5。
如果我们优先算加法的话,那我们算的应该是
∑
\sum_{}
∑(a+3+5/4)*4;
如果我们先算乘法的话,我们算的就是
∑
\sum_{}
∑a*4+3*4+5;
很明显,加法优先会涉及到分数运算,会丢失精度,
但乘法优先可以很完美的避开这一点。
这样的话,每次我们更新lazymul是也要把lazyadd更新一下。
明确了这个之后,还有一个就是2次方和三次方该怎么表示。
首先如果是赋值和乘法的话,那就是直接乘就好啦,主要是加法
∑
(
x
+
c
)
∗
(
x
+
c
)
\sum_{}(x+c)*(x+c)
∑(x+c)∗(x+c)=
∑
x
∗
x
+
2
∗
c
∗
x
+
c
∗
c
\sum_{}x*x+2*c*x+c*c
∑x∗x+2∗c∗x+c∗c
=
∑
x
∗
x
\sum_{}x*x
∑x∗x+
∑
2
∗
c
∗
x
\sum_{}2*c*x
∑2∗c∗x+
∑
c
∗
c
\sum_{}c*c
∑c∗c
=sum2+2*c*sum1+c*c*(区间长度);
同理
∑
(
x
+
c
)
∗
(
x
+
c
)
∗
(
x
+
c
)
\sum_{}(x+c)*(x+c)*(x+c)
∑(x+c)∗(x+c)∗(x+c)
=
∑
x
∗
x
∗
x
\sum_{}x*x*x
∑x∗x∗x+
∑
3
∗
c
∗
x
∗
x
\sum_{}3*c*x*x
∑3∗c∗x∗x+
∑
3
∗
c
∗
c
∗
x
\sum_{}3*c*c*x
∑3∗c∗c∗x+
∑
c
∗
c
∗
c
\sum_{}c*c*c
∑c∗c∗c
=sum3+3*c*sum2+3*c*c*sum1+c*c*c*(区间长度)
想到这,这道题就差不多可以解决啦,不过这个代码真的不怎么好些们一定要细心,细心,再细心。
具体代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=1e5+7;
const LL mod=10007;
LL sum1[maxn<<2],sum2[maxn<<2],sum3[maxn<<2];
LL lazy[maxn<<2],lazyadd[maxn<<2],lazymul[maxn<<2];
LL L[maxn<<2],R[maxn<<2];
void push_up(int rt)
{
sum1[rt]=(sum1[rt<<1]+sum1[rt<<1|1])%mod;
sum2[rt]=(sum2[rt<<1]+sum2[rt<<1|1])%mod;
sum3[rt]=(sum3[rt<<1]+sum3[rt<<1|1])%mod;
}
void build(int l,int r,int rt)
{
lazy[rt]=lazyadd[rt]=0;
lazymul[rt]=1;
L[rt]=l,R[rt]=r;
if(l==r)
{
sum1[rt]=sum2[rt]=sum3[rt]=0;
return ;
}
int m=(l+r)>>1;
build(lson),build(rson);
push_up(rt);
}
void push_down(int rt)
{
///change
if(lazy[rt])
{
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
///lazy不为0的话要把lazyadd和lazymul标记清空
lazyadd[rt<<1]=lazyadd[rt<<1|1]=0;
lazymul[rt<<1]=lazymul[rt<<1|1]=1;
sum1[rt<<1]=(lazy[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
sum2[rt<<1]=(lazy[rt]*lazy[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
sum3[rt<<1]=(lazy[rt]*lazy[rt]*lazy[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
sum1[rt<<1|1]=(lazy[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
sum2[rt<<1|1]=(lazy[rt]*lazy[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
sum3[rt<<1|1]=(lazy[rt]*lazy[rt]*lazy[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
///更新完之后记得初始化
lazy[rt]=0;
}
///mul
if(lazymul[rt]!=1)
{
lazymul[rt<<1]=(lazymul[rt<<1]*lazymul[rt])%mod;
lazymul[rt<<1|1]=(lazymul[rt<<1|1]*lazymul[rt])%mod;
///更新lazymul标记时切记要把lazyadd标记也更新
lazyadd[rt<<1]=(lazyadd[rt<<1]*lazymul[rt])%mod;
lazyadd[rt<<1|1]=(lazyadd[rt<<1|1]*lazymul[rt])%mod;
sum1[rt<<1]=(sum1[rt<<1]*lazymul[rt])%mod;
sum2[rt<<1]=(sum2[rt<<1]*lazymul[rt]*lazymul[rt])%mod;
sum3[rt<<1]=(sum3[rt<<1]*lazymul[rt]*lazymul[rt]*lazymul[rt])%mod;
sum1[rt<<1|1]=(sum1[rt<<1|1]*lazymul[rt])%mod;
sum2[rt<<1|1]=(sum2[rt<<1|1]*lazymul[rt]*lazymul[rt])%mod;
sum3[rt<<1|1]=(sum3[rt<<1|1]*lazymul[rt]*lazymul[rt]*lazymul[rt])%mod;
///更新完之后记得初始化
lazymul[rt]=1;
}
///add
if(lazyadd[rt])
{
lazyadd[rt<<1]=(lazyadd[rt<<1]+lazyadd[rt])%mod;
lazyadd[rt<<1|1]=(lazyadd[rt<<1|1]+lazyadd[rt])%mod;
///根据推导的公式更新sum3,sum2和sum1
sum3[rt<<1]=(sum3[rt<<1]+3LL*lazyadd[rt]*sum2[rt<<1]+3LL*lazyadd[rt]*lazyadd[rt]*sum1[rt<<1]+lazyadd[rt]*lazyadd[rt]*lazyadd[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
sum2[rt<<1]=(sum2[rt<<1]+2LL*lazyadd[rt]*sum1[rt<<1]+lazyadd[rt]*lazyadd[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
sum1[rt<<1]=(sum1[rt<<1]+lazyadd[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
sum3[rt<<1|1]=(sum3[rt<<1|1]+3LL*lazyadd[rt]*sum2[rt<<1|1]+3LL*lazyadd[rt]*lazyadd[rt]*sum1[rt<<1|1]+lazyadd[rt]*lazyadd[rt]*lazyadd[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
sum2[rt<<1|1]=(sum2[rt<<1|1]+2LL*lazyadd[rt]*sum1[rt<<1|1]+lazyadd[rt]*lazyadd[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
sum1[rt<<1|1]=(sum1[rt<<1|1]+lazyadd[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
///更新完之后记得初始化
lazyadd[rt]=0;
}
}
void update(int L1,int R1,LL val,int l,int r,int rt)
{
if(L1<=l&&r<=R1)
{
lazy[rt]=val,lazymul[rt]=1,lazyadd[rt]=0;
sum1[rt]=(val*(R[rt]-L[rt]+1LL))%mod;
sum2[rt]=(val*val*(R[rt]-L[rt]+1LL))%mod;
sum3[rt]=(val*val*val*(R[rt]-L[rt]+1LL))%mod;
return ;
}
push_down(rt);
int m=(l+r)>>1;
if(L1<=m) update(L1,R1,val,lson);
if(R1>m) update(L1,R1,val,rson);
push_up(rt);
}
void updateadd(int L1,int R1,LL val,int l,int r,int rt)
{
if(L1<=l&&r<=R1)
{
lazyadd[rt]=(lazyadd[rt]+val)%mod;
sum3[rt]=(sum3[rt]+3LL*val*sum2[rt]+3LL*val*val*sum1[rt]+val*val*val*(R[rt]-L[rt]+1LL))%mod;
sum2[rt]=(sum2[rt]+2LL*val*sum1[rt]+val*val*(R[rt]-L[rt]+1LL))%mod;
sum1[rt]=(sum1[rt]+(R[rt]-L[rt]+1LL)*val)%mod;
return ;
}
push_down(rt);
int m=(l+r)>>1;
if(L1<=m) updateadd(L1,R1,val,lson);
if(R1>m) updateadd(L1,R1,val,rson);
push_up(rt);
}
void updatemul(int L1,int R1,LL val,int l,int r,int rt)
{
if(L1<=l&&r<=R1)
{
lazymul[rt]=(lazymul[rt]*val)%mod;
lazyadd[rt]=(lazyadd[rt]*val)%mod;
sum1[rt]=(sum1[rt]*val)%mod;
sum2[rt]=(sum2[rt]*val*val)%mod;
sum3[rt]=(sum3[rt]*val*val*val)%mod;
return ;
}
push_down(rt);
int m=(l+r)>>1;
if(L1<=m) updatemul(L1,R1,val,lson);
if(R1>m) updatemul(L1,R1,val,rson);
push_up(rt);
}
LL query(int L1,int R1,int opt,int l,int r,int rt)
{
if(L1<=l&&r<=R1)
{
if(opt==1) return sum1[rt];
if(opt==2) return sum2[rt];
if(opt==3) return sum3[rt];
}
push_down(rt);
LL ans=0;
int m=(l+r)>>1;
if(L1<=m) ans=(ans+query(L1,R1,opt,lson))%mod;
if(R1>m) ans=(ans+query(L1,R1,opt,rson))%mod;
return ans%mod;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)&&n&&m)
{
build(1,n,1);
while(m--)
{
int opt,x,y;
LL c;
scanf("%d%d%d%lld",&opt,&x,&y,&c);
if(opt==1) updateadd(x,y,c,1,n,1);
else if(opt==2) updatemul(x,y,c,1,n,1);
else if(opt==3) update(x,y,c,1,n,1);
else printf("%lld\n",query(x,y,c,1,n,1));
}
}
return 0;
}