并查集-hdu3083-How Many Answers Are Wrong

http://acm.hdu.edu.cn/showproblem.php?pid=3038
就是给你x,y,z让[x,y]的和为z;
问顺序下去有多少错;
这可以看出并查集,就是y比x-1大z
然后如果y,z-1在同一个集合,直接验证答案;
不然就把他们合起来;
为了路径压缩,我们就要链接x-1,y的祖先;
当然我们链接x-1,y祖先的时候要保证x-1,y的距离为z;
所以这个时候有两种方法;
xx=get(x-1)
yy=get(y)
fa[xx]=yy和fa[yy]=xx;是不同的;
因为这里是边权并查集所以有一个g[]数组
怎么说呢,你们自己理解一下;

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int fa[1000001],g[1000001];
int ff,n,m,x,y,z,nn,ans;
int get(int x){
    if(fa[x]==x)return x;
    int f=get(fa[x]);
    g[x]+=g[fa[x]];
    fa[x]=f;
    return f;
}
void merge(int xx,int yy,int z){
    if(xx<yy){
        fa[yy]=xx;
        g[yy]=g[x]+z-g[y];
    }else{
        fa[xx]=yy;
        g[xx]=g[y]-g[x]-z;
    }
}
int main()
{
while(scanf("%d%d",&n,&m)==2){
    for(int i=0;i<=n;i++)fa[i]=i;
    memset(g,0,sizeof g);
    ans=0;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        x--;
        int xx=get(x);
        int yy=get(y);
        if(xx==yy)
            if(g[y]-g[x]!=z)ans++;else;
        else merge(xx,yy,z);
    }
    printf("%d\n",ans);
}
} 

我那个程序merge的时候,采取的方法是把xx,yy里面大的接到小的后面;这样的话,g[]里面一定是非负数;
如果把小的接到大的话,g[]里面会出现负数;
但好像出现负数没什么关系,都会抵消掉的;

posted @ 2017-03-01 07:51  largecube233  阅读(103)  评论(0编辑  收藏  举报