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\n",ans); 57 } 58 return 0; 59 } 60 /***********************************************************************************************************************************************************************************************************************