标签:
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)"1 x y c",代表 把区间 [x,y] 上的值全部加c。(2)"2 x y c",代表 把区间 [x,y] 上的值全部乘以c。(3)"3 x y c" 代表 把区间 [x,y]上的值全部赋值为c。
(4)"4 x y p" 代表 求区间 [x,y] 上值的p次方和1<=p<=3。
思路:
首先先解决一个区间内可能同时出现+和*的操作的问题(如果出现赋值,则在赋值之前的+和*都是无效的),我们可以把加法累计起来,把乘法先处理了,比如说原来[l,r]这一段上有了+x,现在要求*y,我们可以先把原来的每个数乘以y,然后加上x*y,即都是先处理乘法,在处理加法。
然后处理一下区间查询的问题,假设原来的值是k,如果是乘法或者赋值的话,sumv1,sumv2,sumv3的修改是很容易实现的,如果是加,(p+k)^3=p^3+3*p^2*k+3*k^2*p+k^3,所以sumv3[rt]=sumv3[rt]+sumv2[rt]*3*k+sumv1[rt]*3*k+(r-l+1)*k^3,同理二次方的修改也是如此
#include<bits/stdc++.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn=110100;
typedef long long ll;
const int MOD=10007;
ll sumv1[maxn*4],sumv2[maxn*4],sumv3[maxn*4],v,op,setv[maxn*4],mul[4*maxn],addv[4*maxn];
int L,R;
void build(int l,int r,int rt){
sumv1[rt]=0,sumv2[rt]=0,sumv3[rt]=0;
setv[rt]=addv[rt]=mul[rt]=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(lson);
build(rson);
}
void pushup(int rt){
sumv1[rt]=(sumv1[rt<<1]+sumv1[rt<<1|1])%MOD;
sumv2[rt]=(sumv2[rt<<1]+sumv2[rt<<1|1])%MOD;
sumv3[rt]=(sumv3[rt<<1]+sumv3[rt<<1|1])%MOD;
}
void change(int op,int rt,int l,int r,ll k){
if(op==1){
sumv3[rt]=(sumv3[rt]+sumv2[rt]*3*k+3*k*k*sumv1[rt]%MOD+k*k*k%MOD*(r-l+1))%MOD;
sumv2[rt]=(sumv2[rt]+k*k*(r-l+1)+2*k*sumv1[rt])%MOD;
sumv1[rt]=(sumv1[rt]+k*(r-l+1))%MOD;
}
else if(op==2){
sumv3[rt]=sumv3[rt]*(k*k*k%MOD)%MOD;
sumv2[rt]=sumv2[rt]*k*k%MOD;
sumv1[rt]=sumv1[rt]*k%MOD;
}
else{
sumv3[rt]=(k*k*k%MOD)*(r-l+1)%MOD;
sumv2[rt]=k*k*(r-l+1)%MOD;
sumv1[rt]=k*(r-l+1)%MOD;
}
}
void pushdown(int rt,int l,int r){
if(setv[rt]!=0){
int mid=(l+r)>>1;
change(3,rt<<1,l,mid,setv[rt]);
change(3,rt<<1|1,mid+1,r,setv[rt]);
setv[rt<<1]=setv[rt<<1|1]=setv[rt];
addv[rt<<1]=addv[rt<<1|1]=0;
mul[rt<<1]=mul[rt<<1|1]=0;
setv[rt]=0;
}
if(mul[rt]!=0){
int mid=(l+r)>>1;
change(2,rt<<1,l,mid,mul[rt]);
change(2,rt<<1|1,mid+1,r,mul[rt]);
if(mul[rt<<1]==0)
mul[rt<<1]=mul[rt];
else
mul[rt<<1]=mul[rt<<1]*mul[rt]%MOD;
if(mul[rt<<1|1]==0)
mul[rt<<1|1]=mul[rt];
else
mul[rt<<1|1]=mul[rt<<1|1]*mul[rt]%MOD;
addv[rt<<1]=addv[rt<<1]*mul[rt]%MOD;
addv[rt<<1|1]=addv[rt<<1|1]*mul[rt]%MOD;
mul[rt]=0;
}
if(addv[rt]!=0){
int mid=(l+r)>>1;
change(1,rt<<1,l,mid,addv[rt]);
change(1,rt<<1|1,mid+1,r,addv[rt]);
addv[rt<<1]=(addv[rt<<1]+addv[rt])%MOD;
addv[rt<<1|1]=(addv[rt<<1|1]+addv[rt])%MOD;
addv[rt]=0;
}
}
void update(int l,int r,int rt){
if(L<=l&&R>=r){
if(op==3){
setv[rt]=v,mul[rt]=0,addv[rt]=0;
change(op,rt,l,r,v);
}
else if(op==2){
if(mul[rt]==0)
mul[rt]=v;
else
mul[rt]=mul[rt]*v%MOD;
addv[rt]=addv[rt]*v%MOD;
change(op,rt,l,r,v);
}
else{
addv[rt]=(addv[rt]+v)%MOD;
change(op,rt,l,r,v);
}
return ;
}
pushdown(rt,l,r);
int mid=(l+r)>>1;
if(L<=mid)
update(lson);
if(R>mid)
update(rson);
pushup(rt);
}
ll query(int l,int r,int rt){
if(L<=l&&R>=r){
if(v==1)
return sumv1[rt];
if(v==2)
return sumv2[rt];
return sumv3[rt];
}
pushdown(rt,l,r);
int mid=(l+r)>>1;
ll ans=0;
if(L<=mid)
ans+=query(lson);
if(R>mid)
ans+=query(rson);
return ans;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0&&m==0)
break;
build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%d%d%d%lld",&op,&L,&R,&v);
if(op==4)
printf("%lld\n",query(1,n,1)%MOD);
else
update(1,n,1);
}
}
return 0;
}Hdu 4578 Transformation(区间加值,区间乘值,区间赋值,查询区间的p次方)
标签:
原文地址:http://blog.csdn.net/acm_fighting/article/details/51366348