P6554 Promises I Can't Keep
作者:互联网
首先要把题目分析清楚
假如每个点作为根节点 所有叶节点到该根节点的路径权值和 除以 以该节点为根节点的叶节点个数
这个除以操作很烦 我们想办法先去掉 (一般这种除以什么的都要先乘上 最后再除)
所以我们先不考虑除以这个操作,因为以该节点为根节点的叶节点个数我们单独维护还是很好维护的-->cnt[]数组
这个题很容易想到换根dp
先找到一个一定不是叶节点的点作为根节点 然后遍历一遍整个树 依次考虑将根为另一个点所产生的价值差
假设rt是我们一开始认定的根节点 目前我们位于u点,我们已经算到以他的dp值(就是其他叶节点到他的路径权值和)
to是u的一个儿子
分两种情况
如果to是叶节点 则 将根换做to dp[to]=dp[u]-(val[to]+val[u])+val[to]×(cnt[rt]-1)
如果to不是叶结点 则 dp[to]=dp[u]-cnt[to]×val[u]+(cnt[rt]-cnt[to])×val[to]
最后统计一下ans就好
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
int n,rt;
int vis[maxn];
double dp[maxn],val[maxn],cnt[maxn];
double ans=-1e9;
vector<int>Q[maxn];
void dfs(int u,int fa);
void dff(int u,int fa);
int main(){
cin>>n;
for(int aa,bb,i=1;i<n;i++)
cin>>aa>>bb,Q[aa].push_back(bb),Q[bb].push_back(aa);
for(int i=1;i<=n;i++)cin>>val[i];
for(int i=1;i<=n;i++)
if(Q[i].size()!=1){
rt=i;break;
}
dfs(rt,0);
dff(rt,0);
for(int i=1;i<=n;i++)
ans=max(ans,dp[i]/(cnt[rt]-vis[i]));
printf("%.4lf\n",ans);
return 0;
}
void dfs(int u,int fa){
for(int i=0;i<Q[u].size();i++){
int to=Q[u][i];
if(to==fa)continue;
dfs(to,u);
cnt[u]+=cnt[to];
dp[u]+=dp[to];
}
dp[u]+=val[u]*cnt[u];
if(!cnt[u])dp[u]=val[u],cnt[u]=1,vis[u]=1;
}
void dff(int u,int fa){
for(int i=0;i<Q[u].size();i++){
int to=Q[u][i];
if(to==fa)continue;
if(vis[to])
dp[to]=dp[u]-val[u]+val[to]*(cnt[rt]-2);
else dp[to]=dp[u]-val[u]*cnt[to]+val[to]*(cnt[rt]-cnt[to]);
dff(to,u);
}
}
标签:Promises,val,int,cnt,Keep,P6554,maxn,节点,dp 来源: https://www.cnblogs.com/wzxbeliever/p/16095744.html