一、题目
二、解法
考虑每个点为终点的贡献,然后乘上概率直接相加求得答案。
设终点为 x x x,考虑起点到终点的这条路径,每走到一个错误的 z z z就要付出 2 s i z [ z ] 2siz[z] 2siz[z]的代价,走到错误的 z z z的概率是 1 2 \frac{1}{2} 21(考虑排列就是有一个在前,有一个在后,在前为错误,概率就为 1 2 \frac{1}{2} 21),那么期望就是 s i z [ z ] siz[z] siz[z],这样就比较好算了,考虑每一条 ( x , y ) (x,y) (x,y)的边,如果 y y y是儿子,那么对答案的贡献为 s i z [ y ] × v a l [ y ] × e d [ x ] siz[y]\times val[y]\times ed[x] siz[y]×val[y]×ed[x],其中 v a l [ y ] val[y] val[y]就是 y y y子树的起点概率之和,那么 y y y是父亲的情况也不难推导了,时间复杂度 O ( n ) O(n) O(n)
#include <cstdio>
#define db double
const int M = 100005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,tot,f[M],siz[M];
db ans,sums,sumt,val[M],st[M],ed[M];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
}e[2*M];
void dfs(int u,int fa)
{
siz[u]=1;
val[u]=st[u];
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
val[u]+=val[v];
}
}
signed main()
{
n=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
e[++tot]=edge(v,f[u]),f[u]=tot;
e[++tot]=edge(u,f[v]),f[v]=tot;
}
for(int i=1;i<=n;i++)
{
scanf("%lf %lf",&st[i],&ed[i]);
sums+=st[i];
sumt+=ed[i];
}
for(int i=1;i<=n;i++)
{
st[i]=st[i]/sums;
ed[i]=ed[i]/sumt;
}
dfs(1,0);
for(int u=1;u<=n;u++)
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(siz[v]>=siz[u])
ans+=(1-val[u])*(n-siz[u])*ed[u];
else
ans+=val[v]*siz[v]*ed[u];
}
printf("%.10lf\n",ans);
}