Conquer a New Region HDU - 4424(带权并查集的dp)

The wheel of the history rolling forward, our king conquered a new region in a distant continent.
There are N towns (numbered from 1 to N) in this region connected by several roads. It’s confirmed that there is exact one route between any two towns. Traffic is important while controlled colonies are far away from the local country. We define the capacity C(i, j) of a road indicating it is allowed to transport at most C(i, j) goods between town i and town j if there is a road between them. And for a route between i and j, we define a value S(i, j) indicating the maximum traffic capacity between i and j which is equal to the minimum capacity of the roads on the route.
Our king wants to select a center town to restore his war-resources in which the total traffic capacities from the center to the other N - 1 towns is maximized. Now, you, the best programmer in the kingdom, should help our king to select this center.
Input
There are multiple test cases.
The first line of each case contains an integer N. (1 <= N <= 200,000)
The next N - 1 lines each contains three integers a, b, c indicating there is a road between town a and town b whose capacity is c. (1 <= a, b <= N, 1 <= c <= 100,000)
Output
For each test case, output an integer indicating the total traffic capacity of the chosen center town.
Sample Input
4
1 2 2
2 4 1
2 3 1
4
1 2 1
2 4 1
2 3 1
Sample Output
4
3
问题是如果首先确定了根,那么就很好求了,关键是不知道根,后来想了缩小规模看看,就知道根了,假设把两个子树合并了,那么根肯定是在两颗子树之一的地方,那么这个合成的树的路径必然经过这个连接边,到这就卡了,后来想如果这个边的权值是小与所有这两颗子树的边 ,那么当确定了一个根,那么连接到另一颗子树的值只能是这条最小边,所有想到把边排序了,从大到小合并,还有一个问题,合并了的新树的根一定是两颗子树的跟之一么,的确如此,因为假设选其他根,答案不会更大。
所有需要知道一个树的大小和维护这个树当前的答案,这么合并树,就是带权并查集,通过并查集实现dp的思想

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200005

using namespace std;
int pre[N];
long long ans[N];
int num[N];
int  findd(int x)
{
    return pre[x]==x?x:findd(pre[x]);
}
struct node
{
    int x1,x2;
    int w;
}edge[N];
int n;
void init()
{
    for(int i=1;i<=n;i++)
        pre[i]=i;
    for(int i=1;i<=n;i++)
        num[i]=1;
    memset(ans,0,sizeof(ans));
}
int cmp(node p1,node p2)
{
    return p1.w>p2.w;
}
int main()
{
    int x,y,w;
    while(scanf("%d",&n)==1)
    {
        init();
        for(int i=1;i<n;i++)
            scanf("%d%d%d",&edge[i].x1,&edge[i].x2,&edge[i].w);
        sort(edge+1,edge+n,cmp);
        for(int i=1;i<n;i++)
        {
            int xx=findd(edge[i].x1);
            int yy=findd(edge[i].x2);
            ans[xx]+=(long long)edge[i].w*num[yy];
            ans[yy]+=edge[i].w*num[xx];
            if(ans[xx]>ans[yy])//选哪个点作为新树的根
            {
                num[xx]+=num[yy];
                pre[yy]=xx;
            }
            else
            {
                num[yy]+=num[xx];
                pre[xx]=yy;
            }
        }
        printf("%lld\n",ans[findd(1)]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值