[HDU 3038]How Many Answers Are Wrong[并查集]

题目链接:[HDU 3038]How Many Answers Are Wrong[并查集]

题意分析:

给出区间值的和,问这些话中有多少个是和之前矛盾的。

解题思路:

用一个dis数组记录点到根节点的距离(也就是从该节点到根节点的整个区间和),那么当所给出的区间两点的根节点相同时,就可以进行判断。例如这两个区间端点是l和r。那么整个区间的总和就是dis[l] - dis[r]。由于区间l,r是闭区间,所以在这里我们记录的时候让l--,这样减出来的区间就是所求的区间。当根节点不同时,就对其进行合并,默认左边并到右边。具体见代码~

个人感受:

这一类型的并查集题目卡了好几天了,今天总算收尾了。这道题的理解让POJ 1733变得容易理解:)

具体代码如下:

#include<cstdio>

const int MAXN = 2e5 + 111;

int p[MAXN], dis[MAXN], ans; // dis[x]代表x到根结点的距离

int find(int x)
{
    if (p[x] == x) return x;
    int t = p[x];
    p[x] = find(p[x]); // 这里的整个处理就是更新dis[x]
    dis[x] += dis[t];  // 例如:A->B->C,A本来只指向B,现在更新到C。那么dis[A](A->C) = dis[B](B->C) + dis[A](A->B);
    return p[x];       // 每一次压缩路径都会使得dis变成从这个节点,指向其根节点的距离。
}

bool unite(int x, int y, int sum)
{
    int rx = find(x), ry = find(y);
    if (rx == ry)
    {
        if (dis[x] - dis[y] == sum)
            return 0;
        else return 1;
    }
    else
    {
        p[rx] = ry;
        // dis[rx] = rx -> ry
        // dis[y]  = y  -> ry
        // dis[x]  = x  -> rx
        // sum     = x  -> y
        // 显然答案就是下面这个式子了
        dis[rx] = dis[y] + sum - dis[x];
        return 0;
    }
}

int main()
{
    int n, m, ans = 0, a, b, sum;
    while(~scanf("%d%d", &n, &m))
    {
        ans = 0;
        for (int i = 0; i <= n; ++i) p[i] = i, dis[i] = 0;
        for (int i = 0; i < m; ++i)
        {
            scanf("%d%d%d", &a, &b, &sum);
            --a;
            if (unite(a, b, sum)) ++ans;
        }
        printf("%d\n", ans);
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值