Conquer a New Region UVA - 1664

题意: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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值