●BZOJ 2752 [HAOI2012]高速公路(road)
题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=2752
题解:
期望,线段树。
把每个路段看成一个点,那么对于l~R的操作,就可以转化为对l~r(r=R-1)的路段的操作。
对于每个询问,我们只需要依次考虑每个路段出现在多少个区间里面。
令cnt[i]表示i号路段在cnt[i]个区间包含。
即答案为$$\frac{\sum_{i=l}^{r}v[i]*cnt[i]}{(r-l+1)*(r-l+2)/2(区间总数)}$$
那么就需要在线维护一些,使得能够快速求出上面的值。
考虑每个路段的贡献:
i号路段被(i-l+1)*(r-i+1)个区间包含,
所以贡献为:(i-l+1)*(r-i+1)*v[i],把其展开:
=(l+r)*i*v[i]-l*r*v[i]-l*v[i]+r*v[i]-i*i*v[i]+v[i]。
所以,我们只需要用线段树维护每个区间的路段的v[i]的和,i*v[i]的和,i*i*v[i]的和;
代码:
#include<bits/stdc++.h> #define MAXN 100005 using namespace std; long long sumi[MAXN],sumi2[MAXN]; struct SGT{ int size,root; int ls[MAXN*2],rs[MAXN*2],lazy[MAXN*2]; long long sumval[MAXN*2],sumival[MAXN*2],sumi2val[MAXN*2]; void Pushup(int u){ sumval[u]=sumval[ls[u]]+sumval[rs[u]]; sumival[u]=sumival[ls[u]]+sumival[rs[u]]; sumi2val[u]=sumi2val[ls[u]]+sumi2val[rs[u]]; } void Add(int &u,int l,int r,int v){ if(!u) u=++size; sumval[u]+=1ll*(r-l+1)*v; sumival[u]+=(sumi[r]-sumi[l-1])*v; sumi2val[u]+=(sumi2[r]-sumi2[l-1])*v; lazy[u]+=v; } void Pushdown(int u,int l,int mid,int r){ Add(ls[u],l,mid,lazy[u]); Add(rs[u],mid+1,r,lazy[u]); lazy[u]=0; } void Modify(int &u,int l,int r,int al,int ar,int v){ if(!u) u=++size; if(al<=l&&r<=ar) return Add(u,l,r,v); int mid=(l+r)>>1; if(lazy[u]) Pushdown(u,l,mid,r); if(al<=mid) Modify(ls[u],l,mid,al,ar,v); if(mid<ar) Modify(rs[u],mid+1,r,al,ar,v); Pushup(u); } long long Contribution(int u,int al,int ar){ return sumival[u]*(al+ar)-sumval[u]*al*ar-sumval[u]*al+sumval[u]*ar-sumi2val[u]+sumval[u]; // return sumival[u]*(al+ar)-sumval[u]*al*ar+sumval[u]*ar-sumival[u]-sumi2val[u]; } long long Query(int u,int l,int r,int al,int ar){ if(!u) return 0; if(al<=l&&r<=ar) return Contribution(u,al,ar); int mid=(l+r)>>1; long long ret=0; if(lazy[u]) Pushdown(u,l,mid,r); if(al<=mid) ret+=Query(ls[u],l,mid,al,ar); if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar); return ret; } }DT; int N,M; long long gcd(long long a,long long b){ while(b^=a^=b^=a%=b); return a; } int main(){ char ch; int l,r,v; scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) sumi[i]=sumi[i-1]+i,sumi2[i]=sumi2[i-1]+1ll*i*i; for(int i=1;i<=M;i++){ scanf(" %c %d %d",&ch,&l,&r); r--; if(ch=='C') scanf("%d",&v),DT.Modify(DT.root,1,N,l,r,v); else { long long a=DT.Query(DT.root,1,N,l,r); long long b=1ll*(r-l+1)*(r-l+2)/2; long long g=gcd(a,b); a/=g; b/=g; printf("%lld/%lld\n",a,b); } } return 0; }
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas