题意:给出一个有$N$个点的树,你最开始在$1$号点,经过第$i$条边需要花费$w_i$的时间。每条边只能被经过$2$次。求出到达除$1$号点外所有点的最早时间的最小平均值。$N \leq 10^5 , w \leq 1000$
设$f_i$表示以第$i$个点为子树的最小总时间,考虑由儿子向父亲合并,额外定义$dis_i$为$i$到其父亲的边的边权,$t_i$表示从$t$的父亲走完根节点为$t$的子树再回到$t$的时间,也就等于$(\text{子树边权和+与父亲相连的边的边权})\times 2$,再定义$size_i$表示以$i$为根节点的子树的点数。可以$t_i$与$size_i$都是很容易从儿子向父亲合并的。
设我们正在算点$x$的答案,其儿子为$y_1,y_2...y_k$,且它们的答案已经算出来了。那么它的父亲的答案也就是$\sum\limits_{i=1}^k (f_{y_i}+dis_i \times size_i) + \sum\limits_{i=1}^k t_{p_i} \times (size_x - 1 - \sum\limits_{j=1}^i size_{p_i})$,其中$p_1,p_2...p_k$是一个$y_1,y_2...y_k$的排列,因为子树的选择是无序的,而在选择某个子树的时候,剩下没有选的所有点都需要等待这棵子树遍历完。
那么现在我们的任务转变为了找到一个最优的$p_1,p_2...p_k$的选择。考虑这个排列可能与排序有关,所以我们使用邻项交换的方法分析是否具有贪心策略。考虑相邻两个元素$p_i,p_i+1$,因为交换对于其他元素的答案是没有影响的,所以我们只需要考虑$p_i$与$p_{i+1}$的差别,将其他的设为$W$。
当我们的顺序是$p_i,p_{i+1}$时,答案是$f_{p_i}+t_{p_i} \times size_{p_{i+1}}+f_{p_{i+1}}+W$,而当顺序为$p_{i+1},p_i$时答案为$f_{p_{i+1}}+t_{p_{i+1}} \times size_{p_i}+f_{p_i}+W$。我们令第一种方案优于第二种方案,所以$f_{p_i}+t_{p_i} \times size_{p_{i+1}}+f_{p_{i+1}}+W < f_{p_{i+1}}+t_{p_{i+1}} \times size_{p_i}+f_{p_i}+W$,可以得到$t_{p_i} \times size_{p_{i+1}} < t_{p_{i+1}} \times size_{p_i}$。所以我们使用这个公式进行排序,就可以得到最优的方案。
1 #include<bits/stdc++.h> 2 #define ld long double 3 #define MAXN 500010 4 #define int long long 5 using namespace std; 6 7 inline int read(){ 8 int a = 0; 9 bool f = 0; 10 char c = getchar(); 11 while(!isdigit(c)){ 12 if(c == '-') 13 f = 1; 14 c = getchar(); 15 } 16 while(isdigit(c)){ 17 a = (a << 3) + (a << 1) + (c ^ '0'); 18 c = getchar(); 19 } 20 return f ? -a : a; 21 } 22 23 struct Edge{ 24 int end , upEd , w; 25 }Ed[MAXN]; 26 int head[MAXN] , siz[MAXN] , T[MAXN] , N , cntEd , forC; 27 ld dp[MAXN]; 28 29 bool cmp(int a , int b){ 30 return T[a] * siz[b] < T[b] * siz[a]; 31 } 32 33 inline void addEd(int a , int b , int c){ 34 Ed[++cntEd].end = b; 35 Ed[cntEd].upEd = head[a]; 36 Ed[cntEd].w = c; 37 head[a] = cntEd; 38 } 39 40 void dfs(int now){ 41 siz[now] = 1; 42 vector < int > v; 43 for(int i = head[now] ; i ; i = Ed[i].upEd) 44 if(!siz[Ed[i].end]){ 45 dfs(Ed[i].end); 46 siz[now] += siz[Ed[i].end]; 47 T[Ed[i].end] += Ed[i].w << 1; 48 dp[Ed[i].end] += Ed[i].w * siz[Ed[i].end]; 49 v.push_back(Ed[i].end); 50 } 51 sort(v.begin() , v.end() , cmp); 52 for(int i = 0 ; i < v.size() ; i++){ 53 dp[now] += T[now] * siz[v[i]] + dp[v[i]]; 54 T[now] += T[v[i]]; 55 } 56 } 57 main(){ 58 N = read(); 59 for(int i = 1 ; i < N ; i++){ 60 int a = read() , b = read() , c = read(); 61 addEd(a , b , c); 62 addEd(b , a , c); 63 } 64 dfs(1); 65 cout << fixed << setprecision(8) << dp[1] * 1.0 / (N - 1); 66 return 0; 67 }