-
首有个朴素的想法就是设(f_i)表示考虑完子树后节点(i)通电的概率,然后换根(dp)一下。
-
但是这样不好算:因为这样算的是自己本身有电,或者儿子有电的概率。
-
考虑转化一下,(f_i)表示考虑完子树后节点(i)没电的概率,然后换根(dp)一下。
-
这样的好处在于算的是自己本身有电,并且儿子有电的概率。
-
这样就可以直接乘起来了,即
[f_i=(1-v_i)*prod (f_v+(1-f_v)*(1-w_v))
]
- 最后换根一下考虑每个节点作为根节点的概率。
- 复杂度(O(n))
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define R register int
#define db double
using namespace std;
const int N=1000001;
int n,u,v,cnt;db x,f[N],w[N],vl[N],ans;
int hd[N],to[N],nt[N];
void link(R f,R t,db d){nt[++cnt]=hd[f],to[cnt]=t,w[cnt]=d,hd[f]=cnt;}
int gi(){
R x=0,k=1;char c=getchar();
while(c!='-'&&(c<'0'||c>'9'))c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
void Dfs1(R i,R fm){
f[i]=1.00-vl[i];
for(R k=hd[i];k;k=nt[k])
if(to[k]!=fm){
Dfs1(to[k],i);
f[i]*=(f[to[k]]+(1.00-w[k])*(1.00-f[to[k]]));
}
}
void Dfs2(R i,R fm){
ans+=1.00-f[i];
for(R k=hd[i];k;k=nt[k]){
if(to[k]==fm)continue;
db u=f[i],v=f[to[k]];
f[i]/=(f[to[k]]+(1.00-w[k])*(1.00-f[to[k]]));
f[to[k]]*=(f[i]+(1.00-w[k])*(1.00-f[i]));
Dfs2(to[k],i);
f[i]=u,f[to[k]]=v;
}
}
int main(){
n=gi();
for(R i=1;i<n;++i){
u=gi(),v=gi(),scanf("%lf",&x);
x/=100.0,link(u,v,x),link(v,u,x);
}
for(R i=1;i<=n;++i)scanf("%lf",&vl[i]),vl[i]/=100.0;
Dfs1(1,0),Dfs2(1,0),printf("%.6lf
",ans);
return 0;
}