[bzoj3566][SHOI2014]概率充电器【树形dp】
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=3566
【题解】
套路题求出一个的解,然后换根。
*注意除0的问题。
/* --------------
user Vanisher
problem bzoj-3566
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 500010
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
struct node{
int data,next;
long double vote;
}e[N*2];
int place,head[N],n,st[N*5],id,cnt[N];
void build(int u, int v,long double w){
e[++place].data=v; e[place].next=head[u]; head[u]=place; e[place].vote=w;
e[++place].data=u; e[place].next=head[v]; head[v]=place; e[place].vote=w;
}
long double p[N],ans[N],now[N],rd[N*5];
long double solve(int x, int fa){
now[x]=0;
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (e[ed].data!=fa){
double nex=(p[e[ed].data]+(1-p[e[ed].data])*solve(e[ed].data,x))*e[ed].vote;
if (cnt[e[ed].data]!=0) nex=e[ed].vote;
if (nex==1) cnt[x]++;
else now[x]=now[x]+(1-now[x])*nex;
}
return now[x];
}
void dfs(int x, int fa){
st[++id]=x;
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (e[ed].data!=fa){
rd[id]=e[ed].vote;
dfs(e[ed].data,x);
st[++id]=x;
rd[id-1]=e[ed].vote;
}
}
int main(){
n=read();
for (int i=1; i<n; i++){
int u=read(), v=read();
long double w=read()/100.0;
build(u,v,w);
}
for (int i=1; i<=n; i++)
p[i]=read()/100.0;
solve(1,0);
dfs(1,0);
for (int i=1; i<=id; i++){
if (cnt[st[i]]>0)
ans[st[i]]=0;
else ans[st[i]]=1-(p[st[i]]+(1-p[st[i]])*now[st[i]]);
if (i<id){
int x=st[i], y=st[i+1];
double tmp=(p[y]+(1-p[y])*now[y])*rd[i];
if (tmp==1||(cnt[y]>0&&rd[i]==1)) cnt[x]--;
else now[x]=(now[x]-tmp)/(1-tmp);
tmp=(p[x]+(1-p[x])*now[x])*rd[i];
if (tmp==1||(cnt[x]>0&&rd[i]==1)) cnt[y]++;
else now[y]=now[y]+(1-now[y])*tmp;
}
}
long double maxans=0;
for (int i=1; i<=n; i++)
maxans=maxans+ans[i];
printf("%.6Lf\n",n-maxans);
return 0;
}