【模板】带权并查集 HDU 3038

具体学习参考https://blog.csdn.net/sunmaoxiang/article/details/80959300#commentBox

这篇博客也是我觉得比较好理解的方法——向量法,具体体现在代码。

hdu 3038 区间和悖论问题

这里写图片描述

假如说区间【fx,x】是之前建立的区间,他们之间和为sum[x],fx和x的联系可以用集合来存储,同理【fy,y】也是如此。当给出了一个新的区间【x,y】时,且区间和为s。就产生了两种情况了,如果fx == fy 那么这两个区间是有关联的区间,也就是【x,y】之间的和是可以求出的。可以把这个图看成一个向量。 区间【x,y】的和就是可以写成sum[x] - sum[y]。判断给出的s与向量法计算的区间和是否相等就可以判断是否是悖论。 
当然如果fx != fy就需要建议新的区间关系。首先将fy指向fx,这代表fx是区间的左端点,计算sum【fy】= sum【x】- sum【y】+ s;这里同样用的是向量法。 
这样建立联系与判断悖论都可以表达了,接下来就是一些细节了,比如在更新区间的时候要进行路径的压缩,压缩的过程中需要对权值进行更新,目的是使每个已知区间最大化。 

#include<iostream>
using namespace std;
const int maxn=200005;
int sum[maxn],pre[maxn];
int n,m;
void init()
{
    for(int i=0; i<=n; i++)
    {
        pre[i]=i;
        sum[i]=0;
    }
}
int find(int x)
{
    if(x==pre[x])
        return x;
    else
    {
        int root=find(pre[x]);
        sum[x]+=sum[pre[x]];
        return pre[x]=root;
    }
}
int main()
{

    while(cin>>n>>m)
    {
        init();
        int cnt=0;
        for(int i=0; i<m; i++)
        {
            int p,q,s;
            cin>>p>>q>>s;
            p--;
            int fp=find(p),fq=find(q);
            if(fp!=fq)
            {
                pre[fp]=fq;
                sum[fp]=sum[q]-sum[p]+s;
            }
            else if(sum[p]-sum[q]!=s)   cnt++;
        }
        cout<<cnt<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Dilly__dally/article/details/84503191