【解题报告】HDU 3038 How Many Answers Are Wrong (带权并查集)

原题链接

参考dalao的解法

真开心!今天又学到(TLE)了新知识(N多发)呢!

题意

有n个数组成的序列,然后有m条信息,每次信息有3个数据a,b,c,告诉你a到b的数之和为c,要求你求得这些信息里有多少个信息是逻辑错误的。

思路

这个题目看上去像是线段树或树状数组之类的,但实际上这类让你从很多句信息中找矛盾的题目都和并查集脱不了干系,但是这中并查集还从来没见过呢T。T,于是只好百度补知识了。不得不说dalao的思维真是厉害呢,这种用向量的思维代替合并的想法非常巧妙。
我们定义sum[x]为x到其father的和,然后对于每一对读到的a和b,我们先常规方法搜它的father。
如果father一样,那么很显然我们有判断 sum[a-1] - sum[b] 是否和c相等(题目定义了a<b,而我们在合并的时候也是满足将b作为a的father所以如果a和b的father相等那么a一定是离他们的公共father较远的那个点)。
如果father不一样,那么我们就要去合并a和b这两个集合啦!常规操作嘛!但是合并的时候注意我们需要更新sum[fa[a]]。这里我们很巧妙的向量思维就派上用场了。
在这里插入图片描述
看!如果有向量知识的话,我们很容易知道,把fa[b]作为fa[a]的祖先之后,我们就需要把sum[fa[a]]更新一下(祖先节点的sum一直都是0,除非它不再是祖先节点)
那么就是要求向量roota -> rootb,这个很容易从图中看出来等于 -sum[a]+c+sum[b]。
好啦,我们现在差不多已经写完了,但是还有一个地方要注意的,这样写的话,我们的findfather函数就不能简单地写成那一行的递归形式了,我们要在每次调用的时候及时地更新sum[x]的值,如果x的祖先发生改变的话,不及时更新可能会得到错误的答案。
findfather函数这样写:

int findfather(int x)
{
    if(fa[x] != x)
    {
        int temp = fa[x];
        fa[x] = findfather(fa[x]);
        sum[x] += sum[temp];//这一步做出更新sum[x]的操作,注意在这之前x原来的祖先节点也就是temp的值已经在递归中被更新了,所以可以放心更新。
    }
    return fa[x];
}

好啦,总的代码就在下面了!

#include <iostream>
#include <cstdio>
#define maxn 200010
int sum[maxn];
int fa[maxn];
using namespace std;
int findfather(int x)
{
    if(fa[x] != x)
    {
        int temp = fa[x];
        fa[x] = findfather(fa[x]);
        sum[x] += sum[temp];
    }
    return fa[x];
}

int main()
{
    int n, m;
    while(scanf("%d %d", &n, &m) != EOF)
    {
        int ans = 0;
        for(int i=0; i<=n; i++)
        {
            fa[i] = i;
            sum[i] = 0;
        }
        while(m--)
        {
            int x, y, z;
            scanf("%d %d %d", &x, &y, &z);
            x--;
            int t1 = findfather(x);
            int t2 = findfather(y);
            if(t1 == t2)
            {
                if(z != sum[x]-sum[y])
                  ans++;
            }
            else
            {
                fa[t1] = t2;
                sum[t1] = -sum[x]+sum[y]+z;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42772300/article/details/88725821