CF123E Maze

子节点顺序被打乱,每个点可以回溯一次,每条边边权都为1,给你每个点为起点和终点的概率,问你我们访问这个树的期望长度

结论

若父亲为 xx 要访问的节点为 yy 显然 zz 若在 yy 前面则访问 yy 的时候距离会加 2size[z]2size[z] 并且这个概率时12\frac{1}{2} 因此,父亲到儿子期望的走的距离为 sz[father]sz[father] 或者是sz[son[t]]+1\sum{sz[son[t]]}+1

此时我们记录在 tt 子树中为起点的概率之和为 sumsum

这个点 tt 为终点的概率为 yy

那么答案就是 sumsz[t]ysum*sz[t]*y

不在这个子树中的同理,枚举每一个点为终点记录答案即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<iomanip>

#define int long long

using namespace std;

const int maxn=100100;

double ans;

int n,m,head[maxn],size;
int _x[maxn],_y[maxn];
int sz[maxn],val[maxn];
int xsum,ysum,f[maxn];

struct edge{
int next,to,lok;
}e[maxn<<1];

inline void addedge(int next,int to)
{
e[++size].to=to;
e[size].lok=next;
e[size].next=head[next];
head[next]=size;
}

void dfs(int t,int fat)
{
int i,j;
sz[t]=1;
f[t]=fat;
for(i=head[t];i;i=e[i].next)
{
j=e[i].to;
if(j==fat) continue;
dfs(j,t);
sz[t]+=sz[j];
val[t]+=val[j];
}
}

signed main()
{
ios::sync_with_stdio(false);
register int i,j;
cin>>n;
int t1,t2;
for(i=1;i<n;i++)
{
cin>>t1>>t2;
addedge(t1,t2);
addedge(t2,t1);
}
for(i=1;i<=n;i++)
{
cin>>_x[i]>>_y[i];
xsum+=_x[i];
ysum+=_y[i];
val[i]=_x[i];
}
dfs(1,0);
for(i=1;i<=size;i++)
{
t1=e[i].lok;
t2=e[i].to;
if(f[t1]==t2)
{
ans+=((double)((n-sz[t1])*(xsum-val[t1]))/xsum)*((double)_y[t1])/ysum;
}
else
{
ans+=(double)(sz[t2]*((double)val[t2])/xsum)*(double)_y[t1]/ysum;
}
}
cout<<fixed<<setprecision(9)<<ans<<endl;
return 0;
}