题意:给一棵树,多次询问$a$到$b$期望步数,每一步都是随机的
对期望DP了解更深入了一些
先预处理$up_x$表示从$x$走到$fa_x$的期望步数
可以直接往上走,也可以先去儿子再回来,设$x$的度数为$d_x$
所以$up_x=\dfrac{1}{d_x}+\sum\limits_{p\in son_x}\dfrac{1}{d_x}\left(1+up_p+up_x\right)$
整理得$up_x=d_x+\sum\limits_{p\in son_x}up_p$
再预处理$down_x$表示从$fa_x$走到$x$的期望步数
可以直接往下走,也可以先去其他儿子再回来,也可以先去爷爷再回来
所以$down_x=\dfrac{1}{d_x}+\dfrac{1}{d_x}\left(1+down_{fa_x}+down_x\right)+\sum\limits_{\substack{p\in son_{fa_x}\\p\ne x}}\dfrac{1}{d_x}\left(1+up_p+down_x\right)$
整理得$down_x=down_{fa_x}+up_{fa_x}-up_x$
dp求出$up$和$down$之后求前缀和,用倍增求lca,一上一下的期望直接加起来即可
#include<stdio.h>
#define ll long long
int to[200010],nex[200010],h[100010],d[100010],dep[100010],fa[100010][17],tot;
ll up[100010],dn[100010];
void add(int a,int b){
tot++;
to[tot]=b;
nex[tot]=h[a];
h[a]=tot;
}
void dfs1(int x){
up[x]=d[x];
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x][0]){
fa[to[i]][0]=x;
dep[to[i]]=dep[x]+1;
dfs1(to[i]);
up[x]+=up[to[i]];
}
}
}
void dfs2(int x){
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x][0]){
dn[to[i]]=dn[x]+up[x]-up[to[i]];
dfs2(to[i]);
}
}
}
void dfs3(int x){
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x][0]){
up[to[i]]+=up[x];
dn[to[i]]+=dn[x];
dfs3(to[i]);
}
}
}
void swap(int&a,int&b){a^=b^=a^=b;}
int lca(int x,int y){
int i;
if(dep[x]<dep[y])swap(x,y);
for(i=16;i>=0;i--){
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(i=16;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int main(){
int n,m,i,j,a,b;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d%d",&a,&b);
d[a]++;
d[b]++;
add(a,b);
add(b,a);
}
dep[1]=1;
dfs1(1);
for(j=1;j<17;j++){
for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
}
dfs2(1);
dfs3(1);
scanf("%d",&m);
while(m--){
scanf("%d%d",&a,&b);
j=lca(a,b);
printf("%lld\n",up[a]-up[j]+dn[b]-dn[j]);
}
}