容易知道,除了根节点之外,下面的儿子节点如果是全树权值最大的点一定会在父亲节点染色之后被染色。
假如现在有x,y,z三个节点,现在知道x和y的染色是连续的。
那么先染x,y再染z的代价是x+2y+3z
如果先z后x和y那么代价是z+2x+3y
都加上(z-y)后再除以2,就是(x+y)/2+2z和z+(x+y)
也就是(x+y)/2和z谁先染色的代价
于是同理可知多个点的合并节点等价代价为sum/点数
然后不断合并就好了
1 /* *********************************************** 2 Author :BPM136 3 Created Time :2018/7/16 11:36:59 4 File Name :2054.cpp 5 ************************************************ */ 6 7 #include<iostream> 8 #include<cstdio> 9 #include<algorithm> 10 #include<cstdlib> 11 #include<cmath> 12 #include<cstring> 13 #include<vector> 14 using namespace std; 15 16 typedef long long ll; 17 typedef vector<int> VI; 18 19 const int N = 1005; 20 21 int c[N],a[N]; 22 int fa[N]; 23 int n,root; 24 VI b[N]; 25 bool vis[N]; 26 27 int main() { 28 while(scanf("%d%d",&n,&root)!=EOF) { 29 if(n==0 && root==0) return 0; 30 for(int i=1;i<=n;i++) { 31 scanf("%d",&c[i]); 32 a[i]=c[i]; 33 } 34 for(int i=1;i<n;i++) { 35 int p,f; 36 scanf("%d%d",&f,&p); 37 fa[p]=f; 38 } 39 for(int i=1;i<=n;i++) { 40 b[i].clear(); 41 b[i].push_back(i); 42 } 43 for(int i=1;i<=n;i++) vis[i]=0; 44 vis[root]=1; 45 for(int o=1;o<n;o++) { 46 int v=0; 47 double mx=0.0; 48 for(int i=1;i<=n;i++) if(vis[i]==0) { 49 if(a[i]*1.0/b[i].size()>mx) { 50 mx=a[i]*1.0/b[i].size(); 51 v=i; 52 } 53 } 54 int f=fa[v]; 55 vis[v]=1; 56 for(int i=0;i<b[v].size();i++) b[f].push_back(b[v][i]); 57 a[f]+=a[v]; 58 for(int i=1;i<=n;i++) if(vis[i]==0 && fa[i]==v) { 59 fa[i]=f; 60 } 61 } 62 ll ans=0; 63 for(int i=0;i<b[root].size();i++) ans+=(long long)(i+1)*c[ b[root][i] ]; 64 printf("%lld ",ans); 65 } 66 return 0; 67 }