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

 

  

 

posted @ 2018-03-10 20:50  *ZJ  阅读(119)  评论(0编辑  收藏  举报