题意:给出N个点,N-1条边,每个边有一个容量。定义两个城市之间的容量为两个城市之间路径的上边的的容量的最小值。现在希望设立一个中心城市,使该城市到其他城市的容量之和最大。
思路:因为对于每条路径,实际限制容量的是最小的那一条边。这样,我们就可以对边的容量从小到大对边进行排序,进行添加。利用并查集来维护一堆城市的最大容量。合并时,按照合并后的容量进行合并。
代码如下:
#include <cstdio>
#include <algorithm>
#include <functional>
#include <cstring>
using namespace std;
typedef long long ll;
struct edge{
int u, v;
ll w;
edge(int uu = 0, int vv = 0, ll ww = 0):u(uu), v(vv), w(ww){}
bool operator < (const edge & e)const{
return w > e.w;
}
};
const int MAX = 200020;
edge G[MAX];
int N;
int tot;
ll sum[MAX];
int fa[MAX];
int num[MAX];
void init()
{
tot = 0;
memset(sum,0,sizeof(sum));
for(int i = 1; i <= N; ++i)
fa[i] = i,num[i] = 1;
}
int find(int u)
{
return u == fa[u]? u: fa[u] = find(fa[u]);
}
void unite(edge & e)
{
int u = e.u, v= e.v;
u = find(u),v = find(v);
ll sum1 = sum[u] + e.w * num[v];
ll sum2 = sum[v] + e.w * num[u];
if(u != v){
if(sum1 > sum2){
sum[u] += e.w * num[v];
fa[v] = u;
num[u] += num[v];
}
else{
sum[v] += e.w * num[u];
fa[u] = v;
num[v] += num[u];
}
}
}
int main(void)
{
//freopen("input.txt","r",stdin);
while(scanf("%d", &N) != EOF){
init();
for(int i = 0; i < N - 1; ++i)
scanf("%d %d %lld",&G[i].u,&G[i].v,&G[i].w);
sort(G,G + N - 1);
for(int i = 0; i < N - 1; ++i)
unite(G[i]);
printf("%lld\n",sum[find(1)]);
}
return 0;
}