题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4578
★这题有有3个操作,需要考虑的因素比较多,
题意:
有n个数,4种操作
①:把[ l , r ]的每个数加上c
②:把[ l , r ]的每个数乘上c
③:把[ l , r ]的每个数变成c
④:输出[ l , r ]之间的数的 k次方的和 k=1,2,3
思路:
首先要明确的一点,前三种操作都需要用 懒标记(lazy_tag),故需要三个标记(记为add , mult ,rep)
在询问的时候,可能是区间和、区间平方和、区间立方和,不妨维护这三个值(记为 sum1 ,sum2 ,sum3)
然后问题来了,当标记下传的时候,怎么处理这三个懒标记的关系呢?
初始化的时候add=0, mult=1, rep=0
当进行了操作三,很明显add=0 mult=1
进行操作二时,要 add[k]=add[k]*v%mod;
这样就可以默认每次是 先乘再加的了
然后就是简单的公式推导了 疯狂取模
当 (rep[ k ] != 0)时
sum1=∑( tmp )
sum2=∑( tmp )2
sum3=∑( tmp )3
当 (add[ k ] != 0 || mult[ k ] != 1)时
sum1= ∑(ab+c)
sum2= ∑(ab+c) 2
sum3= ∑(ab+c) 3
把他们化简开就是代码中那段很长的式子了
代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int maxn=1e5+5;
const int sz=1<<10;
const int mod=1e4+7;
const int inf=2e9;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
int n,m;
int sum1[maxn<<2],sum2[maxn<<2],sum3[maxn<<2];
int add[maxn<<2],mult[maxn<<2],rep[maxn<<2];
template<class t>
inline void read(t &x)
{
char c; x=1;
while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
t res=c-'0';
while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
x*=res;
}
void build(int k,int l,int r)
{
mult[k]=1;
add[k]=rep[k]=0;
sum1[k]=sum2[k]=sum3[k]=0;
if(l==r) return ;
int mid=l+r>>1;
build(ls); build(rs);
}
void pushdown(int k,int l,int r,int mid)
{
if(rep[k]!=0){
rep[k<<1]=rep[k<<1|1]=rep[k];
rep[k]=0;
add[k<<1]=add[k<<1|1]=0;
mult[k<<1]=mult[k<<1|1]=1;
int tmp=rep[k<<1];
sum1[k<<1]=(mid-l+1)*tmp%mod;
sum2[k<<1]=sum1[k<<1]*tmp%mod;
sum3[k<<1]=sum2[k<<1]*tmp%mod;
sum1[k<<1|1]=(r-mid)*tmp%mod;
sum2[k<<1|1]=sum1[k<<1|1]*tmp%mod;
sum3[k<<1|1]=sum2[k<<1|1]*tmp%mod;
}
if(add[k]!=0||mult[k]!=1){
add[k<<1]=(add[k<<1]*mult[k]%mod+add[k])%mod;
add[k<<1|1]=(add[k<<1|1]*mult[k]%mod+add[k])%mod;
mult[k<<1]=mult[k<<1]*mult[k]%mod;
mult[k<<1|1]=mult[k<<1|1]*mult[k]%mod;
int b=mult[k],c=add[k];
//(a^3*b^3+3*a^2*b^2*c+3*a*b*c^2+c^3)
//(a^2*b^2+2*a*b*c+c^2)
sum3[k<<1]=(b*b%mod*b%mod*sum3[k<<1]%mod+3*b%mod*b%mod*c%mod*sum2[k<<1]%mod+3*c%mod*c%mod*b%mod*sum1[k<<1]%mod+(mid-l+1)*c%mod*c%mod*c%mod)%mod;
sum2[k<<1]=(b*b%mod*sum2[k<<1]%mod+2*b%mod*c%mod*sum1[k<<1]%mod+(mid-l+1)*c%mod*c%mod)%mod;
sum1[k<<1]=(b*sum1[k<<1]%mod+(mid-l+1)*c%mod)%mod;
sum3[k<<1|1]=(b*b%mod*b%mod*sum3[k<<1|1]%mod+3*b%mod*b%mod*c%mod*sum2[k<<1|1]%mod+3*c%mod*c%mod*b%mod*sum1[k<<1|1]%mod+(r-mid)*c%mod*c%mod*c%mod)%mod;
sum2[k<<1|1]=(b*b%mod*sum2[k<<1|1]%mod+2*b%mod*c%mod*sum1[k<<1|1]%mod+(r-mid)*c%mod*c%mod)%mod;
sum1[k<<1|1]=(b*sum1[k<<1|1]%mod+(r-mid)*c%mod)%mod;
add[k]=0; mult[k]=1;
}
}
void update(int k,int l,int r,int x,int y,int v,int type)
{
if(x<=l&&r<=y){
v%=mod;
if(type==1){
add[k]=(add[k]+v)%mod;
sum3[k]=(sum3[k]+3*sum2[k]%mod*v%mod+3*sum1[k]%mod*v%mod*v%mod+(r-l+1)*v%mod*v%mod*v%mod)%mod;
sum2[k]=(sum2[k]+2*sum1[k]%mod*v%mod+(r-l+1)*v%mod*v%mod)%mod;
sum1[k]=(sum1[k]+v*(r-l+1)%mod)%mod;
}
else if(type==2){
add[k]=add[k]*v%mod;
mult[k]=mult[k]*v%mod;
sum1[k]=sum1[k]*v%mod;
sum2[k]=sum2[k]*v%mod*v%mod;
sum3[k]=sum3[k]*v%mod*v%mod*v%mod;
}
else{
add[k]=0; mult[k]=1; rep[k]=v;
sum1[k]=(r-l+1)*v%mod;
sum2[k]=sum1[k]*v%mod;
sum3[k]=sum2[k]*v%mod;
}
return ;
}
int mid=l+r>>1;
pushdown(k,l,r,mid);
if(mid>=x) update(ls,x,y,v,type);
if(mid<y) update(rs,x,y,v,type);
sum1[k]=(sum1[k<<1]+sum1[k<<1|1])%mod;
sum2[k]=(sum2[k<<1]+sum2[k<<1|1])%mod;
sum3[k]=(sum3[k<<1]+sum3[k<<1|1])%mod;
}
int query(int k,int l,int r,int x,int y,int type)
{
if(x<=l&&r<=y){
if(type==1) return sum1[k];
else if(type==2) return sum2[k];
return sum3[k];
}
int mid=l+r>>1;
pushdown(k,l,r,mid);
int ans=0;
if(mid>=x) ans=(ans+query(ls,x,y,type))%mod;
if(mid<y) ans=(ans+query(rs,x,y,type))%mod;
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
build(1,1,n);
int op,a,b,c;
while(m--){
read(op); read(a); read(b); read(c);
if(op==4) printf("%d\n",query(1,1,n,a,b,c));
else update(1,1,n,a,b,c,op);
}
}
return 0;
}