题意:n(n <= 200000)个城市形成一颗树,每条边有权值C(i,j)。任意两个点的容量S(i,j)定义为i与j唯一通路上容量的最小值,找一个点,(它将成为中心城市),使得它到其他所有点的容量之和最大。
思路:1.和Kruskal算法类似,即将所有边按照从大到小得顺序排列,通过并查集每次加入一条新边u-v
2.该条边是u集合中心城市到v集合的各个点的容量,同时也是v集合中心城市到u集合的各个点的容量,因此此时需要比较u集合的中心城市再次作为中心城市好还是选择v集合的中心城市
3.过程中需要两个数组进行维护,sum[i]表示i集合的中心城市到i集合各个点容量之和,cnt[i[表示i集合所含点的个数,这里建议两个数组都使用long long(即使n也就是点的总个数不会爆int)
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn = 200000 + 10;
ll sum[maxn];
int n,u[maxn],v[maxn],w[maxn];
int r[maxn],fa[maxn],cnt[maxn];
void init()
{
memset(sum,0,sizeof(sum));
for(int i = 0; i <= n; i++)
{
cnt[i] = 1;
fa[i] = r[i] = i;
}
}
int cmp(const int i,const int j)
{
return w[i] > w[j];
}
int found(int x)
{
if(x == fa[x]) return x;
return fa[x] = found(fa[x]);
}
int main()
{
while(scanf("%d",&n) != EOF)
{
init(); int num = n - 1;
for(int i = 0; i < num; i++) scanf("%d%d%d",&u[i],&v[i],&w[i]);
ll ans = 0; sort(r,r + num,cmp);
for(int i = 0;i < num;i++)
{
int e = r[i];
int x = found(u[e]),y = found(v[e]);
//两数相乘爆int
ll sum1 = sum[x] + cnt[y] * (ll)w[e];
ll sum2 = sum[y] + cnt[x] * (ll)w[e];
if(sum1 > sum2)
{
cnt[x] += cnt[y];
sum[x] = sum1;
fa[y] = x;
ans = sum[x];
}
else
{
cnt[y] += cnt[x];
sum[y] = sum2;
fa[x] = y;
ans = sum[y];
}
}
printf("%lld\n",ans);
}
return 0;
}