[Gym 102135][K - A Boring Problem ]2018 8th BSUIR Open Programming Contest

description

一棵树,(n<=1e5),每次询问两个点s,t,问从s到t的期望步数

每个点走一步将随机的走到与自己相邻的点上。

solution

这种题,从高中就遇到了……

可以将询问拆开考虑:E(s->t)=E(s->lca)+E(lca->t)

我们可以维护两个数组down[x],u[x]分别表示从根节点到x的期望步数,从x到根的期望步数,现在问题变成了怎么求这两个数组

考虑进一步拆分,设d[x],u[x]分别表示从x的父亲节点走到x的期望步数,从x走到父亲的期望步数,那么down[x]和u[x]就是d[x]和u[x]的树上前缀和

先求u[i]:设i的父亲为x,那么此时i的情况有2种:1、直接走到自己父亲,达成目标 2、走到自己的儿子,需要从自己的儿子走上来再去自己的父亲
u [ i ] = 1 + ∑ v ∈ s o n ( x ) u [ v ] + u [ i ] s o n [ i ] + 1 u[i]=1+\dfrac{\sum_{v\in{son(x)}}{u[v]+u[i]}}{son[i]+1} u[i]=1+son[i]+1vson(x)u[v]+u[i]
化 简 得 : u [ i ] = s o n [ i ] + 1 + ∑ v ∈ s o n ( x ) u [ v ] − − − − − ( 1 ) 化简得:u[i]=son[i]+1+\sum_{v\in{son(x)}}{u[v]}-----(1) u[i]=son[i]+1+vson(x)u[v](1)
由于叶子节点的u[x]=1,依次往上累加得到u[i]=2*size[i]-1

然后求d[i],设i的父亲为x,那么此时x的情况有3种:1、直接往下走到i,达成目标 2、走到x的父亲后折回来再走到i 3、走到i的兄弟节点后折回来
d [ i ] = 1 + d [ x ] + d [ i ] + ∑ v ∈ b r o ( i ) u [ v ] + d [ i ] s o n [ x ] + 1 d[i]=1+\dfrac{d[x]+d[i]+\sum_{v\in{bro(i)}}{u[v]+d[i]}}{son[x]+1} d[i]=1+son[x]+1d[x]+d[i]+vbro(i)u[v]+d[i]
化 简 得 : d [ i ] = s o n [ x ] + 1 + d [ x ] + ∑ v ∈ b r o ( i ) u [ v ] 化简得:d[i]=son[x]+1+d[x]+\sum_{v\in{bro(i)}}{u[v]} d[i]=son[x]+1+d[x]+vbro(i)u[v]
带 入 ( 1 ) 得 : d [ i ] = u [ x ] − u [ i ] + d [ x ] = d [ x ] + 2 ∗ s i z e [ x ] − 2 ∗ s i z e [ i ] 带入(1)得:d[i]=u[x]-u[i]+d[x]=d[x]+2*size[x]-2*size[i] 1d[i]=u[x]u[i]+d[x]=d[x]+2size[x]2size[i]
我们发现i是从1-v1-v2……-i的,因此首尾相消得: d [ i ] = d [ v 1 ] + 2 ∗ s i z e [ v 1 ] − 2 ∗ s i z e [ i ] d[i]=d[v1]+2*size[v1]-2*size[i] d[i]=d[v1]+2size[v1]2size[i]

我们可以求一下v1:
d [ i ] = 1 + ∑ v ∈ b r o ( i ) u [ v ] + d [ i ] s o n [ 1 ] d[i]=1+\dfrac{\sum_{v\in{bro(i)}}{u[v]+d[i]}}{son[1]} d[i]=1+son[1]vbro(i)u[v]+d[i]
d [ i ] = s o n [ 1 ] + ∑ v ∈ b r o ( i ) u [ v ] = 2 ∗ n − 2 ∗ s i z e [ i ] − 1 d[i]=son[1]+\sum_{v\in{bro(i)}}{u[v]}=2*n-2*size[i]-1 d[i]=son[1]+vbro(i)u[v]=2n2size[i]1
带入得: d [ i ] = 2 ∗ n − 2 ∗ s i z e [ i ] − 1 d[i]=2*n-2*size[i]-1 d[i]=2n2size[i]1

然后根据上面得推导,求出up[i]和down[i],对每个询问lca一下就好。

code

#include<bits/stdc++.h>
#define LL long long
#define fo(i,a,b) for(LL i=a;i<=b;i++)
#define rp(i,a,b) for(LL i=a;i>=b;i--)
#define tr(t,x) for(LL t=first[x];t;t=nex[t])
using namespace std;
const LL N=1e5+5;
const LL mo=1e9+7;
LL first[N],last[2*N],nex[2*N],siz[N],dep[N];
LL u[N],d[N],up[N],down[N],f[N][20];
LL n,m,i,t,j,k,l,x,y,z,ln,num;
void lian(LL x,LL y){
	last[++num]=y;nex[num]=first[x];first[x]=num;
}
void dg(LL x,LL y){
	siz[x]++;dep[x]=dep[y]+1;
	tr(t,x){
		if (last[t]==y) continue;
		dg(last[t],x);
		siz[x]+=siz[last[t]];
	}
	u[x]=(2*siz[x]-1)%mo;
	d[x]=(2*(n-siz[x])-1)%mo;
	f[x][0]=y;
} 
void dg1(LL x,LL y){
	up[x]=(u[x]+up[y])%mo;
	down[x]=(d[x]+down[y])%mo;
	tr(t,x)
		if (last[t]!=y)dg1(last[t],x);
} 
LL lca(LL x,LL y){
	if (dep[x]<dep[y]) swap(x,y);
	rp(j,ln,0)
		if (dep[f[x][j]]>=dep[y]) x=f[x][j];
	if (x==y) return x;
	rp(j,ln,0)
		if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
	return f[x][0];
}
int main(){
	//freopen("data.in","r",stdin);
	scanf("%lld%lld",&n,&m); 
	fo(i,1,n-1)scanf("%lld%lld",&x,&y),lian(x,y),lian(y,x);
	dg(1,0);
	u[1]=d[1]=0;dg1(1,0);
	ln=log(N)/log(2);
	fo(j,1,ln)
		fo(i,1,n)
			f[i][j]=f[f[i][j-1]][j-1];
	while (m--){
		scanf("%lld%lld",&x,&y);
		t=lca(x,y);
		k=(up[x]-up[t]+down[y]-down[t]+mo*2)%mo; 
		printf("%lld\n",k);
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值