[HAOI2012]高速公路 [线段树 期望]

[HAOI2012]高速公路

bzoj2752 luogu2221

Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。

政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。

无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?

一条链 每次询问区间([l,r])中期望花费

区间([l,r])的期望花费 即一个平均值(egin{align*}frac{sum_{i=l}^rsum_{j=i}^rdis[i][j]}{{r-l+1choose 2}}end{align*}) (因为(dis[i][j],(i>j))的情况和((i<j))的情况是一样的 求平均值 就不用再多算一遍了

考虑第(i)条边的贡献 它总共在((i-l+1)(r-i+1))个区间内 所以化简为(sum_iw[i](i-l+1)(r-i+1))

我将(w[i])表示(i-1 o i)的道路花费 所以第(i)条边在区间([l,r])内贡献了 (w[i]*(i-l+1)(r-i)=w[i]* i *(l+r-1)-w[i]*i^2+r*(1-l))

即线段树(sum w[i]*i,sum w[i]*i^2,sum w[i])

然后注意一些小细节就好 对,注意(l*l)要爆int QAQ

struct node{ll sum1,sum2,sum3,add,pre1,pre2;}t[N<<2];
void pup(int o){
	t[o].sum1=t[ls].sum1+t[rs].sum1,t[o].sum2=t[ls].sum2+t[rs].sum2,t[o].sum3=t[ls].sum3+t[rs].sum3;
}
void updnode(int o,int l,int r,ll k){
	t[o].sum1+=k*t[o].pre1,t[o].sum2+=k*t[o].pre2,t[o].sum3+=((ll)r-l+1)*k,t[o].add+=k;
}
void pudw(int o,int l,int r){
	if(!t[o].add) return;
	int mid=l+r>>1;
	updnode(ls,l,mid,t[o].add),updnode(rs,mid+1,r,t[o].add),t[o].add=0;
}
void upd(int o,int l,int r,int x,int y,ll k){
	if(x>r||y<l) return;
	if(x<=l&&r<=y){updnode(o,l,r,k);return;}
	pudw(o,l,r);
	int mid=l+r>>1;
	upd(ls,l,mid,x,y,k),upd(rs,mid+1,r,x,y,k);
	pup(o);
}
ll d,ans1,ans2,sum1,sum2,sum3;
void query(int o,int l,int r,int x,int y){
	if(x>r||y<l) return;
	if(x<=l&&r<=y){sum1+=t[o].sum1,sum2+=t[o].sum2,sum3+=t[o].sum3;return;}
	pudw(o,l,r);
	int mid=l+r>>1;
	query(ls,l,mid,x,y),query(rs,mid+1,r,x,y);
	pup(o);
	
}
void build(int o,int l,int r){
	if(l==r){t[o]=(node){0,0,0,0,l,(ll)l*l};return;}
	int mid=l+r>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	t[o].pre1=t[ls].pre1+t[rs].pre1,t[o].pre2=t[ls].pre2+t[rs].pre2;
}
ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
	rd(n),rd(m);
	char opt[5];
	build(1,1,n);
	for(int i=1,x,y,k;i<=m;++i){
		scanf("%s",opt);rd(x),rd(y),--y;
		if(opt[0]=='C'){
			rd(k);
			upd(1,1,n,x,y,(ll)k);
		}
		else{
			sum1=sum2=sum3=0ll;query(1,1,n,x,y);++y;
			ans1=sum1*((ll)y+x-1)-sum2+(ll)y*(1-x)*sum3,ans2=((ll)y-x)*((ll)y-x+1)/2;
			d=gcd(ans1,ans2),ans1/=d,ans2/=d;
			if(!ans1) puts("0/1");
			else printf("%lld/%lld
",ans1,ans2);
		}
	}
    return 0; 
}
原文地址:https://www.cnblogs.com/lxyyyy/p/11647746.html