HDU3038带权并查集

看大佬的博客理解了,疑问的地方有两点,一:程序中的距离转换怎么用和根节点的距离来解释? 

二:合并时为什么a--或者b++?直接合并a,b不行吗?这个问题我已经理解了,下面是我的思路:

问题一的思路如图:程序中a,b,x,y四个节点之间距离关系的转换

 

问题二: 为什么不能在unions()函数中直接传入a和b?答案是不能的:需要a--或b++

 

最后,注意程序的连续输入:while(cin>>a>>b) 

#include<iostream>
#include<cstring>
using namespace std;
const int maxn=200005;
int pre[maxn];
int sum[maxn];
int n,m;
int cnt;
void init()
{
    memset(sum,0,sizeof(sum));
    for(int i=0; i<=n+3; i++)
    {
        pre[i]=i;
    }
    cnt=0;
}
int finds(int x)
{
    if(x==pre[x])
        return x;
    int t=pre[x];
    pre[x]=finds(pre[x]);
    sum[x]+=sum[t];//增加量sum[t]是从根节点到当前节点路径上权值之和
    return pre[x];
}
void unions(int a,int b,int s)
{
    int x=finds(a);
    int y=finds(b);
    if(x==y)
    {
        if(sum[a]+s!=sum[b])
            cnt++;
        return;
    }
    else if(x<y)
    {
        pre[y]=x;//将前面点的根节点作为合并之后的根节点
        sum[y]=sum[a]+s-sum[b];
    }
    else//x>y
    {
        pre[x]=y;
        sum[x]=sum[b]-sum[a]-s;
    }
}
int main()
{
    int a,b,s;//有可能是没有连续输入的原因
    while(cin>>n>>m)
    {
        init();
        for(int i=0; i<m; i++)
        {
            cin>>a>>b>>s;
            unions(a-1,b,s);
        }
        cout<<cnt<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41658955/article/details/81366011