首页 > 代码库 > hdu 4037 Development Value(线段树维护数学公式)
hdu 4037 Development Value(线段树维护数学公式)
Development Value
Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 609 Accepted Submission(s): 118
As a crazy fan of SC2, Ahua (flower fairy) play it day and night. Recently, he found that the most important part of being a top player of SC2 is economic development, which means you should get as much mine as possible by training SCVs (space construction vehicle) to collect mine. Train a SCV at ith second costs Ci units of mine. After training, this SCV can collect Di units of mine each second. Training a SCV needs one second of time.
Based on that, he composes a formula to evaluate the development in a time span from xth second to yth second. Assume at xth second, Ahua has no SCV and mine. He trains one SCV at each second during xth second and yth second (the mount of mine can be negative, so that he always can train SCV). Each SCV will collect some amount of mines for Ahua in each second after it was trained. At ith second Ahua has Mi units of mine in total. The development value is defined as sum(Mi) (x ≤ i ≤ y). Now he asks you to help him calculate the development value. To make it more interesting, Ahua can apply following operations:
Cost x y z: the cost of training a SCV between xth second to yth second will increase by z units of mine. i.e. Ci for x ≤ i ≤ y will increase by z.
Collect x y z: each SCV trained between xth second and yth second can collect z more mines every second after it has been trained. i.e. Di for x ≤ i ≤ y will increase by z.
Query x y: output the development value between xth second and yth second.
For each test case, the first line is an integer N (1 ≤ N ≤ 100000), means the maximum time you should deal with.
Following N lines, each contain two integers Ci and Di (0 ≤ Ci, Di ≤ 100000), the cost and collect speed of SCV training in ith second initially as described above.
The next line is an integer Q (1 ≤ Q ≤ 10000), the number of operations you should deal with. Then Q lines followed, each line will be “Cost x y z”, "Collect x y z” or “Query x y”.
1 ≤ x ≤ y ≤ N, 0 ≤ z ≤ 100000
1 5 1 3 2 3 3 1 2 2 3 3 5 Query 1 3 Cost 2 2 1 Query 1 3 Collect 1 1 5 Query 1 3
Case 1: 2 0 15
题意:
有一个游戏。里面要造矿兵。在第i秒造矿兵需要花费c[i]。然后之后的时间每秒该矿兵都会采d[i]的矿。然后询问。从x秒到y秒。每秒造一个矿兵.(在x秒的时候矿兵和矿都为0.但是矿可以为负数)。然后定义了一个mi。表示第i秒时的总矿数。然后要你输出.Σmi(x<=i<=y)。
思路:
先推公式。
1,考虑花费
时刻j 从x时刻到j时刻造农民的总花费
x C(x)
x+1 C(x)+C(x+1)
x+2 C(x)+C(x+1)+C(x+2)
......
y C(x)+C(x+1)+...+C(y)
对第二栏求和,每一列是C(i)*(y-i+1),再对这个从x到y求和,得sigma(C(i)*(y+1-i))
分成两项(y+1)*sigma(C(i))-sigma(C(i)*i)
2,考虑采矿
对于i时刻被造出的农民,到j时刻总共采的矿数是D(i)*(j-i),对这个从x到j求和就是j时刻之前造的农民到j时刻为止总共采的矿数,即sigma(D(i)*(j-i))(对i从x到j求和),再对j从x到y求和就是答案。但是这个形式的求和式不适合用线段树维护,做些变形:
时刻j sigma(D(i)*(j-i))
x D(x)*0
x+1 D(x)*1+D(x+1)*0
x+2 D(x)*2+D(x+1)*1+D(x+2)*0
......
y D(x)*(y-x)+D(x+1)*(y-x-1)+......+D(y-1)*1+D(y)*0
对第二栏求和,每列是D(i)*(y-i)*(y-i+1)/2,再对这个从x到y求和,sigma(D(i)*(y-i)*(y-i+1)/2).
把和式拆成几项方便维护:1/2*( y*(y+1)sigma(D(i)) - (2*y+1)sigma(D(i)*i) + sigma(D(i)*i^2))
然后最后的答案就是采矿-花费。
然后只需要用一颗线段树来维护。
sigma(ci),sigma(i*ci),sigma(di),sigma(i*di),sigma(i*i*di).
然后按一般的更新查询就完了。
对于除二取模的问题。
(1)模数乘2,所有中间过程直接取模,最后得数/2
(2)直接取模,最后答案是ret,如果ret是偶数,答案是ret/2,如果是奇数,答案是(ret + mod) / 2
详细见代码:
#include<algorithm> #include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int INF=0x3f3f3f3f; const int maxn=100010; typedef long long ll; const ll mod=20110911*2; #define lson L,mid,ls #define rson mid+1,R,rs ll sm[maxn],ss[maxn],sc[maxn<<2],sd[maxn<<2],siid[maxn<<2]; ll sic[maxn<<2],sid[maxn<<2],ac[maxn<<2],ad[maxn<<2]; ll asc,aic,asd,aid,aiid; void addc(int L,int R,int rt,ll d) { ac[rt]=(ac[rt]+d)%mod; sc[rt]=(sc[rt]+(R-L+1)*d)%mod; sic[rt]=(sic[rt]+(sm[R]-sm[L-1])*d)%mod; } void addd(int L,int R,int rt,ll d) { ad[rt]=(ad[rt]+d)%mod; sd[rt]=(sd[rt]+(R-L+1)*d)%mod; sid[rt]=(sid[rt]+(sm[R]-sm[L-1])*d)%mod; siid[rt]=(siid[rt]+(ss[R]-ss[L-1])*d)%mod; } void PushDown(int L,int R,int rt) { int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; if(ad[rt]) addd(lson,ad[rt]),addd(rson,ad[rt]),ad[rt]=0; if(ac[rt]) addc(lson,ac[rt]),addc(rson,ac[rt]),ac[rt]=0; } void PushUp(int rt) { int ls=rt<<1,rs=ls|1; sc[rt]=(sc[ls]+sc[rs])%mod; sic[rt]=(sic[ls]+sic[rs])%mod; sd[rt]=(sd[ls]+sd[rs])%mod; sid[rt]=(sid[ls]+sid[rs])%mod; siid[rt]=(siid[ls]+siid[rs])%mod; } void build(int L,int R,int rt) { ac[rt]=ad[rt]=0; if(L==R) { scanf("%I64d%I64d",&sc[rt],&sd[rt]); sic[rt]=(L*sc[rt])%mod; sid[rt]=(L*sd[rt])%mod; siid[rt]=(sid[rt]*L)%mod; return; } int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; build(lson); build(rson); PushUp(rt); } void update(int L,int R,int rt,int l,int r,ll d,int op) { if(l<=L&&R<=r) { if(op) addd(L,R,rt,d); else addc(L,R,rt,d); return; } int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; PushDown(L,R,rt); if(l<=mid) update(lson,l,r,d,op); if(r>mid) update(rson,l,r,d,op); PushUp(rt); //printf("%d->%d sc") } void qu(int L,int R,int rt,int l,int r) { if(l<=L&&R<=r) { asc=(asc+sc[rt])%mod; aic=(aic+sic[rt])%mod; asd=(asd+sd[rt])%mod; aid=(aid+sid[rt])%mod; aiid=(aiid+siid[rt])%mod; return; } int ls=rt<<1,rs=ls|1,mid=(L+R)>>1; PushDown(L,R,rt); if(l<=mid) qu(lson,l,r); if(r>mid) qu(rson,l,r); PushUp(rt); } int main() { int i,t,n,q,x,y,z,cas=1; char cmd[20]; for(i=1;i<maxn;i++) { sm[i]=(sm[i-1]+i)%mod; ss[i]=(ss[i-1]+(ll)i*i)%mod; } scanf("%d",&t); while(t--) { scanf("%d",&n); build(1,n,1); scanf("%d",&q); printf("Case %d:\n",cas++); while(q--) { asc=aic=asd=aid=aiid=0; scanf("%s%d%d",cmd,&x,&y); if(cmd[0]!='Q') scanf("%d",&z); if(cmd[2]=='s') update(1,n,1,x,y,z,0); else if(cmd[2]=='l') update(1,n,1,x,y,z,1); else { qu(1,n,1,x,y); ll ans=((ll)y*(y+1)*asd-(2*y+1)*aid+aiid)%mod; ans-=2*((y+1)*asc-aic); ans%=mod; ans=(ans+mod)%mod; //printf("asc %I64d aic %I64d asd %I64d aid %I64d aiid %I64d\n",asc,aic,asd,aid,aiid); printf("%I64d\n",ans/2); } } } return 0; }
hdu 4037 Development Value(线段树维护数学公式)