标签:
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