codeforces294E(树的重心的应用)

 1 /*****************************************************************************************************************************************************************************************
 2 题意:树中有N个点,从N-1条边中间去除一条边,再构建一条相同长度的边连在两个节点上,使得这N个点仍然构成一棵树.
 3 问新树种任意两个点之间距离的总和最小为多少
 4 题解:
 5     由于边的数量为5000.所以可以直接枚举边.
 6     我们枚举每条边,然后删除这条边,将树分成两个子树,把新边连接第一颗树的节点U和第二课树的节点V.
 7     我们可以发现我们以上操作可以获得的价值为:
 8     子树1中任意两点距离总和+子树2中任意两点距离总和+子树1中任意一点到U的距离和*子树2的节点数量+节点2中任意一点到V的距离和*子树1的节点数量+子树1的节点个数*子树2的几点个数*新边的边权.
 9     易知当枚举的边一定时,子树1的节点数量,子树2的节点数量,子树1中任意2点的距离和,子树2中任意2点的距离和都已经被确定了.
10     我们要做的就是在被枚举的边一定时,找到建边的最优的位置U和V来使得 子树1中任意点到U的距离和 和 子树中任意一点到v的距离和  最小.
11     结合重心的知识,可以发现U,V其实分别是子树1的重心和子树2的重心.   
12 ******************************************************************************************************************************************************************************************/
13 #include<bits/stdc++.h>
14 using namespace std;
15 typedef long long LL;
16 typedef pair<int,int> pii;
17 const int maxn = 5005;
18 const LL INF = 0x3f3f3f3f3f3f3f3fll;
19 int f[maxn],h[maxn],w[maxn],son[maxn];
20 vector<pii> g[maxn];
21 LL d[maxn],s[maxn];
22 inline void dfs(int v, int rt){
23     son[v] = 0, d[v] = 0, s[v] = 0;
24     for(int i = 0; i != g[v].size(); i ++){
25         int u = g[v][i].first;
26         if(u==rt) continue;
27         dfs(u, v);
28         s[v] += s[u] + d[u]*son[v] + d[v]*son[u] + (LL)son[u] * son[v] * g[v][i].second;
29         d[v] += d[u] + (LL)son[u] * g[v][i].second;
30         son[v] += son[u];
31     }
32     son[v] ++;  s[v] += d[v];
33 }
34 inline void dfsw(int v,int rt,LL &minn){
35     minn = min(d[v],minn);
36     for (int i=0; i!=g[v].size(); ++i){
37         int u = g[v][i] . first;
38         if (u==rt) continue;
39         d[u] = d[u] + (d[v]-d[u]-(LL)son[u]*g[v][i].second)+(LL)(son[v]-son[u])*g[v][i].second;
40         son[u] = son[v];
41         dfsw(u,v,minn);
42     }
43 }
44 int main(){
45     for (int n; scanf("%d",&n)!=EOF;){
46         for (int i=1; i<=n; ++i)    g[i].clear();
47         for (int i=1,x,y,z; i<n; ++i)scanf("%d%d%d",&x,&y,&z),f[i] = x,h[i] = y,w[i] = z,g[x].push_back(make_pair(y,z)),g[y].push_back(make_pair(x,z));//F[I]为第I条边的起点,H[I]为第I条边的终点,w[i]为第i条边的权值 
48         LL ans = INF , minn = INF, sum =0;
49         for (int i=1; i<n; ++i){
50             minn = INF;     dfs(f[i],h[i]); dfsw(f[i],h[i],minn);
51             sum = (n-son[f[i]])*minn + s[f[i]];  
52             minn = INF;      dfs(h[i],f[i]); dfsw(h[i],f[i],minn);
53             sum += (n-son[h[i]])*minn+s[h[i]] + (LL) son[f[i]]* son[h[i]] * w[i];
54             ans = min(ans,sum);
55         }
56         printf("%I64d
",ans);
57     }
58     return 0; 
59 }
60 /***********************************************************************************************************************************************************************************************************************
原文地址:https://www.cnblogs.com/juruohx/p/7241910.html