ZOJ 3659 Conquer a New Region(12年长春site E)

本文介绍了一种使用并查集解决特定树形结构问题的方法,即找到树中一个点使得所有点到该点的路径上的边权最小值之和最大。通过将边按权重从大到小排序,并逐步构建并查集来解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处,谢谢http://blog.youkuaiyun.com/acm_cxlove/article/details/7854526       by---cxlove 

题目:给出一棵树,找出一个点,求出所有点到这个点的权值和最大,权值为路径上所有边权的最小值。

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3659 

比赛的时候卡了,一直往DP上想。

结果并查集搞定。

按边排序,从大到小插入,每条边将两个集合连起来,而新加的边是两个集合所有边最小的,那么两个集合中的点交叉的通路最小的边就是新加的,那只要枚举两个集合,a,b是a并入b更优还是b并入a更优就行了。集合内部点已经计算出,相互的只要知道集合中元素的个数就好了。

所以并查集只需要维护一个集合的元素个数,一个集合的总权值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 200005
#define MOD 1000000007
#define LL long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
struct Node
{
    int u,v,w;
    bool operator< (const Node n1) const
    {
        return w>n1.w;
    }
}edge[N];
int cnt[N],pre[N];
LL sum[N];
int find(int a)
{
    return pre[a]=(a==pre[a]?a:find(pre[a]));
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        sort(edge,edge+n-1);
        for(int i=1;i<=n;i++)
        {
            sum[i]=0;
            pre[i]=i;
            cnt[i]=1;
        }
        LL ans=0;
        for(int i=0;i<n-1;i++)
        {
            int ra=find(edge[i].u);
            int rb=find(edge[i].v);
            LL atob=(LL)cnt[ra]*edge[i].w+sum[rb];
            LL btoa=(LL)cnt[rb]*edge[i].w+sum[ra];
            if(atob>btoa)
            {
                pre[ra]=rb;
                cnt[rb]+=cnt[ra];
                sum[rb]=atob;
            }
            else
            {
                pre[rb]=ra;
                cnt[ra]+=cnt[rb];
                sum[ra]=btoa;
            }
            ans=max(ans,max(atob,btoa));
        }
        printf("%lld\n",ans);
    }
    return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值