首先记 (f_u) 表示 (u) 不被以 (u) 为根的子树内点通上电的概率。
不难列出这样一个式子:
(f_u=displaystyle(1-p_u)*prod_{v in subtree u}f_v*e(u,v))
其中 (p_u) 表示直接充 (u) 的概率。
但是这个式子有个 bug,它处理不了给 (u) 导电的点在 (u) 子树外的情况。
那么我们采取换根的思想,记 (g_u) 表示 (u) 不通电的概率,则 (g_u) 可以通过 (u) 的子树和剩余部分计算,子树部分我们已经处理过,而剩余部分可以通过 (u) 的父亲计算,记 (h_u) 表示非 (u) 子树里的点导电给 (u) 的概率。
那么 (h_u = dfrac{g_{fa}}{1-e(fa,u)+e(fa,u)*f_u})
那么 (g_u = f_u*(1-e(fa,u)+e(fa,u)*f_u))
那么答案就是 (displaystyle sum_{i=1}^{n}(1-g_i))。
#include <bits/stdc++.h>
#define reg register
#define ll long long
using namespace std;
const int MAXN = 5e5 + 10;
int n, E, head[MAXN], nxt[MAXN << 1], pnt[MAXN << 1];
double val[MAXN << 1], p[MAXN], f[MAXN], g[MAXN], h[MAXN];
inline void clear() {
E = 0, memset(head, -1, sizeof(head));
}
inline void addedge(int x, int y, double v) {
nxt[E] = head[x], pnt[E] = y, val[E] = v, head[x] = E++;
}
inline void dfs1(int u, int fa) {
f[u] = 1 - p[u];
for(reg int i = head[u]; i != -1; i = nxt[i]) {
int v = pnt[i];
if(v == fa) continue;
dfs1(v, u), f[u] *= (1 - val[i] + val[i] * f[v]);
}
}
inline void dfs2(int u, int fa, int id) {
if(u == 1) g[u] = f[u];
else h[u] = g[fa] / (1 - val[id] + val[id] * f[u]), g[u] = f[u] * (1 - val[id] + val[id] * h[u]);
for(reg int i = head[u]; i != -1; i = nxt[i]) {
int v = pnt[i];
if(v == fa) continue;
dfs2(v, u, i);
}
}
inline void work() {
scanf("%d", &n), clear();
for(reg int i = 1; i < n; ++i) {
int u, v;
double d;
scanf("%d%d%lf", &u, &v, &d), d *= 0.01, addedge(u, v, d), addedge(v, u, d);
}
for(reg int i = 1; i <= n; ++i) scanf("%lf", &p[i]), p[i] *= 0.01;
dfs1(1, 0), dfs2(1, 0, 0);
double ans = 0;
for(reg int i = 1; i <= n; ++i) ans += 1.0 - g[i];
printf("%.6f
", ans);
}
int main() {
int _ = 1;
// scanf("%d", &_);
while(_--) work();
return 0;
}