分析:
当时看到概率期望,光速弃疗
写了一个n^2暴力,30分稳
那我们就来看看正解:
son记录和该节点直接相连的结点个数
两遍dfs
第一遍从叶子向根转移
第二遍dfs稍微有点难理解
第二遍dfs处理以每个点为起点的概率(就是答案啦)
从根向叶子转移
f[1][0]=f[1][1]
//这里写代码片
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const int N=1000010;
const double INF=1e17;
const double eps=1e-8;
int n;
int a[N];
struct node{
int x,y,nxt;
};
node way[N<<1];
int st[N],tot=0,ans,son[N];
double ansx,f[N][2];
int dcmp(double x)
{
if (fabs(x)<eps) return 0;
else if (x>0) return 1;
else return -1;
}
void add(int u,int w)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
tot++;
way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot;
}
void dfs_1(int now,int fa)
{
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa)
son[now]++;
if (fa!=0) son[now]++;
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa)
{
dfs_1(way[i].y,now);
if (fa!=0)
f[now][0]+=f[way[i].y][0]/(double)(son[now]-1);
else f[now][0]+=f[way[i].y][0]/(double)son[now];
}
f[now][0]+=a[now];
}
void dfs_2(int now,int fa)
{
if (now==1) f[now][1]=f[now][0];
else
{
double temp1=(f[fa][1]-a[fa])*son[fa];
double temp2=temp1-f[now][0];
double temp3=(f[now][0]-a[now])*(son[now]-1);
if (son[fa]>1)
f[now][1]=(temp2/(double)(son[fa]-1)+a[fa])/(double)son[now]+temp3/(double)son[now];
else
f[now][1]=a[fa]/(double)son[now]+temp3/(double)son[now];
f[now][1]+=a[now];
}
for (int i=st[now];i;i=way[i].nxt)
if (way[i].y!=fa)
dfs_2(way[i].y,now);
}
int main()
{
freopen("walking.in","r",stdin);
freopen("walking.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<n;i++)
{
int u,w;
scanf("%d%d",&u,&w);
add(u,w);
}
if (n==1) {
printf("1
");
return 0;
}
ansx=INF;
dfs_1(1,0);
dfs_2(1,0);
for (int i=1;i<=n;i++)
if (f[i][1]<ansx)
ansx=f[i][1],ans=i;
printf("%d
",ans);
return 0;
}