题目大意
N个充电器连成一棵树。
第i个充电器有p[i]的概率直接充电。
每条导线有一定几率可以导电。
可以导电的导线形成的联通块中只要存在直接充电的结点整个联通块的充电器均进入充电状态。
问期望进入充电状态的充电器个数
转化为有根树
显然可知我们只需要得到f[i]表示i进入充电状态的概率
那么
ans=∑f[i]
我们把无根树变有根树。
设
a[i]=P(i与i的父亲不连通)+P(i与i父亲连通)∗P(只考虑以i为根的子树的充电器的充电情况i未进入充电状态)
即a[i]表示i的父亲不因为i而进入充电状态的概率。
我们设
g[i]=P(只考虑以i为根的子树的充电器的充电情况i进入充电状态)
则
g[i]=P(i直接进入充电状态)+[1−P(i直接进入充电状态)]∗P(i的至少一个连通儿子在只考虑以其为根的子树的充电情况下进入充电状态)
g[i]=p[i]+(1−p[i])∗(1−P(i的所有儿子要么不连通要么连通但只考虑以其为根的子树的充电情况下未进入充电状态))
g[i]=p[i]+1−p[i]−(1−p[i])∗∏j是i儿子P(j要么不连通要么连通但只考虑以j为根的子树的充电情况下j未进入充电状态)
g[i]=1−(1−p[i])∗∏j是i儿子a[j]
现在我们有了g我们需要算出f,不如再设一个辅助数组b。
b[i]=P(在不考虑以i为根的子树的充电情况下i的父亲进入充电状态)
相当于删去i与其父亲的连边后的f’[i的父亲]。
我们知道
g[i]=1−(1−p[i])∗∏j是i儿子a[j]
1−g[i]=(1−p[i])∗∏j是i儿子a[j]
那么如果设
x=1−1−g[i]a[j]
那x表示的就是删除i与j的连边后按照原来方法计算出的g’[i]
那么
b[i]=f′[i的父亲]=g′[i的父亲]+(1−g′[i的父亲])∗P(删除i爷爷与i父亲的连边后i爷爷进入充电状态)∗P(i爷爷与i父亲连通)
b[i]=1−1−g[i的父亲]a[i]+1−g[i的父亲]a[i]∗b[i的父亲]∗P(i爷爷与i父亲连通)
有了b就可以计算f了
f[i]=g[i]+(1−g[i])∗b[i]∗P(i与i父亲连通)
两遍dfs计算即可。
不过这题会爆栈!只能打人工栈……
注意一些小细节:比如分母为0直接赋值为0……
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const int maxn=500000+10;
int h[maxn],now[maxn],go[maxn*2],next[maxn*2];
db dis[maxn*2];
db a[maxn],b[maxn],g[maxn],f[maxn],p[maxn],q[maxn];
struct dong{
int x,y;
};
dong sta[maxn],zlt;
int i,j,k,l,t,n,m,tot,top;
db ans;
void add(int x,int y,int z){
go[++tot]=y;
dis[tot]=(db)z/100;
next[tot]=h[x];
h[x]=tot;
}
void dfs(){
int t,x,y;
db l;
while (top){
x=sta[top].x;y=sta[top].y;
t=now[x];
if (go[t]==y) t=next[t],now[x]=t;
if (!t){
l=1;
t=h[x];
while (t){
if (go[t]!=y) l*=a[go[t]];
t=next[t];
}
g[x]=1-(1-p[x])*l;
a[x]=1-q[x]+q[x]*(1-g[x]);
top--;
continue;
}
q[go[t]]=dis[t];
zlt.x=go[t];zlt.y=x;
sta[++top]=zlt;
now[x]=next[t];
}
}
void dg(){
int t,x,y;
while (top){
x=sta[top].x;y=sta[top].y;
if (!now[x]){
top--;
continue;
}
if (y&&a[x]) b[x]=1-(1-g[y])/a[x]+(1-g[y])/a[x]*q[y]*b[y];else b[x]=0;
f[x]=g[x]+(1-g[x])*q[x]*b[x];
t=h[x];
now[x]=0;
while (t){
if (go[t]!=y){
zlt.x=go[t];zlt.y=x;
sta[++top]=zlt;
}
t=next[t];
}
}
}
int main(){
freopen("charger.in","r",stdin);freopen("charger.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1){
scanf("%d%d%d",&j,&k,&l);
add(j,k,l);add(k,j,l);
}
fo(i,1,n){
scanf("%d",&t);
p[i]=(db)t/100;
}
fo(i,1,n) now[i]=h[i];
zlt.x=1;zlt.y=0;
sta[top=1]=zlt;
dfs();
fo(i,1,n) now[i]=1;
zlt.x=1;zlt.y=0;
sta[top=1]=zlt;
dg();
fo(i,1,n) ans+=f[i];
printf("%.6lf\n",ans);
}