HDU 4424 Conquer a New Region——并查集

来源:互联网 发布:3m平台 源码 编辑:程序博客网 时间:2024/06/03 20:22

题意:给定n个城市和n-1条边,使得n个城市连通,规定任意两个城市之间的权值等于这两个城市间的所有道路权值的最小值,比如1--2--3--4,1--2的权值为1,2--3的权值为2,3--4的权值为3,则1--4的权值为1,要求选择一个城市,使得这个城市到其他所有城市的权值总和最大。

思路:一条路径如果包含一个权值小的边的话,这条路径的总权值就会变小, 基于这一点,我们应该从权值最大的边开始操作,每次都尽量避免权值小的边影响结果,这就可以用到并查集,把所有边从大到小排序后,从最大的边开始,每次对两个节点进行操作,如果左节点的权值之和 + (右节点的所有子节点数量  + 1) * 当前边的权值 大于 右节点的权值之和 + (左节点的所有子节点数量  + 1) * 当前边的权值, 那么就把右节点连接到左节点,并更新左节点的权值之和和左节点的所有子节点数量之和,否则把左节点连接到右节点,并更新右节点的权值之和和右节点的所有子节点的数量之和。

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>using namespace std;const int maxn = 2 * 1e5 + 10;int n, par[maxn];long long cnt[maxn], val[maxn];struct Edge {    int a, b, c;    bool operator < (const Edge &e) {        return c > e.c;    }}edge[maxn];void init() {    for (int i = 1; i <= n; i++) par[i] = i;    memset(cnt, 0, sizeof(cnt));    memset(val, 0, sizeof(val));}int seek(int x) { return par[x] == x ? x : par[x] = seek(par[x]); }int main() {    while (scanf("%d", &n) == 1) {        init();        for (int i = 0; i < n - 1; i++) {            scanf("%d %d %d", &edge[i].a, &edge[i].b, &edge[i].c);        }        sort(edge, edge + n - 1);        for (int i = 0; i < n - 1; i++) {            int a = edge[i].a, b = edge[i].b, c = edge[i].c;            a = seek(a), b = seek(b);            if (val[a] + (cnt[b] + 1) * c > val[b] + (cnt[a] + 1) * c) {                par[b] = a;                cnt[a] = cnt[a] + cnt[b] + 1;                val[a] = val[a] + (cnt[b] + 1) * c;            }            else {                par[a] = b;                cnt[b] = cnt[b] + cnt[a] + 1;                val[b] = val[b] + (cnt[a] + 1) * c;            }        }        printf("%lld\n", val[seek(1)]);    }    return 0;}


原创粉丝点击