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; }