hdu 3038(带权并查集)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3038

思路:sum[x]表示区间[x,f[x]]的和,这个可以在路径压缩的时候更新,对于一组数据(u,v,w),令r1=Find(u),r2=Find(v),于是若r1==r2,此时u,v就有了相同的参考点,而sum[u]为区间[u,r1(r2)]的和,sum[v]为区间[v,r2(r1)]的和,于是只需判断w==sum[v]-sum[u]即可;若r1<r2,此时可以分为两种情况,(u,v,r1,r2)或者(u,r1,v,r2),对于情况1来说,此时father[r1]=r2,sum[r1]=sum[v]-(sum[u]-w);对于情况2有sum[r1]=w-sun[u]+sum[v].通过观察,我们可以发现情况1和情况2的结果是一样的,于是可以合并。同理,对于r1>r2这种情况也一样,这里就不在赘述了。

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstring>

 4 #include<algorithm>

 5 using namespace std;

 6 #define MAXN 222222

 7 int sum[MAXN],father[MAXN];

 8 int n,m;

 9 

10 void Initiate()

11 {

12     memset(sum,0,sizeof(sum));

13     for(int i=0;i<=n;i++)

14         father[i]=i;

15 }

16 

17 int Find(int x)

18 {

19     if(x==father[x])return x;

20     int tmp=father[x];

21     father[x]=Find(father[x]);

22     sum[x]+=sum[tmp];

23     return father[x];

24 }

25 

26 bool Union(int u,int v,int w)

27 {

28     int r1=Find(u),r2=Find(v);

29     if(r1==r2){

30         if(sum[u]==w+sum[v])return true;

31         return false;

32     }else {

33         father[r1]=r2;

34         sum[r1]=sum[v]-sum[u]+w;

35         return true;

36     }

37 }

38 

39 int main()

40 {

41     int u,v,w,ans;

42     while(~scanf("%d%d",&n,&m)){

43         Initiate();

44         ans=0;

45         while(m--){

46             scanf("%d%d%d",&u,&v,&w);

47             if(!Union(u-1,v,w))ans++;

48         }

49         printf("%d\n",ans);

50     }

51     return 0;

52 }
View Code

 

你可能感兴趣的:(HDU)