这是一个非常有趣(not intersting)的题
传送门 https://www.luogu.com.cn/problem/P6554
dp[x] = sigm dp[p] + list[x]*cnt[x]
ans = dp[x] / cnt[x]
利用换根dp枚举一下就好了,转移有点恶心,因为当儿子是叶子的时候,cnt要改变,当父亲是叶子的时候,cnt还有变化
因为实在不会处理叶子当root的情况,所以干脆直接让度数大于1的节点当根了。。。。。
具体看代码吧
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<string>
using namespace std;
const int maxn = 5e5+11;
double list[maxn];
double dp[maxn],cnt[maxn];
int f[maxn];
vector<int>G[maxn];
void add(int x,int y){
G[x].push_back(y);
}
int dfs(int x,int fa){
int ff = 0;
dp[x] = 0;
cnt[x] = 0;
for(int i=0;i<G[x].size();i++){
int p = G[x][i];
if(p == fa) continue;
dfs(p,x);
ff++;
cnt[x] += cnt[p];
dp[x] += dp[p];
}
dp[x] += list[x] * cnt[x];
if(ff == 0) {
f[x] =1;
cnt[x] = 1;
dp[x] = list[x];
return 0;
}
}
int dfs2(int x,int fa){
for(int i=0;i<G[x].size();i++){
int p = G[x][i];
if(p == fa) continue;
double cns = dp[x] - dp[p] - list[x]*cnt[p];
dp[p] -= list[p]*cnt[p];
dp[p] += cns;
if(f[x]){
cnt[p]++;
if(f[p]) cnt[p]--;
}
else{
if(f[p]) cnt[p] = cnt[x]-1;
else cnt[p] = cnt[x];
}
dp[p] += list[p]*cnt[p];
dfs2(p,x);
}
return 0;
}
int de[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
de[x]++;
de[y]++;
}
for(int i=1;i<=n;i++){
scanf("%lf",&list[i]);
}
double ans = -1e17;
int root = 1;
for(int i=1;i<=n;i++){
if(de[i] > 1) {
root = i;
break;
}
}
dfs(root,-1);
dfs2(root,-1);
for(int i=1;i<=n;i++){
ans = max(ans,dp[i]/cnt[i]);
}
printf("%.4lf
",ans);
return 0;
}