并查集

一.普通并查集

int find(int x){
    if(f[x]==x)return x;
    return f[x]=find(f[x]);
}

 

二.带权并查集

int find(int x){
    if(f[x]==x)return x;
    find(f[x]);
    work();//用儿子与爷爷关系和(儿子与父亲关系和父亲与爷爷关系)的关联,更新权值为儿子与爷爷关系
    return f[x]=f[f[x]];
}

 

http://cogs.pro/cogs/problem/problem.php?pid=298

/******************************************************************

                            带权并查集
                            
Part I - 权值(relation)的确定。
        我们可以用动物之间“相对”的关系来确定一个并查集。
        0 - 这个节点与它的父节点是同类
        1 - 这个节点被它的父节点吃
        2 - 这个节点吃它的父节点。
        第一个数字(下文中,设为d)指定了后面两种动物的关系:
        1 - X与Y同类
        2 - X吃Y


Part II - 路径压缩,以及节点间关系确定
    (1)路径压缩节点时的算法
        通过穷举我们可以发现
        f[now]=f[f[now]]
        relation[now]=(relation[now]+relation[f[now]]) % 3
        推理过程 
        父亲是自己 relation[now]=0;0+0=0; 
        父亲不是自己 
爷爷(可能还是父亲)和 父亲和儿子   儿子与爷爷
        0          0      (i + j)%3 = 0
        0          1      (i + j)%3 = 1
        0          2      (i + j)%3 = 2
        1          0      (i + j)%3 = 1
        1          1      (i + j)%3 = 2
        1          2      (i + j)%3 = 0
        2          0      (i + j)%3 = 2
        2          1      (i + j)%3 = 0
        2          2      (i + j)%3 = 1
        注:要先更新父亲再更新儿子,可以直接跳到根节点
    (2)集合间关系的确定
        relation[find(y)]=(relation[x]-relation[y]+(d-1)+3) % 3;
        证明:
            y与find(x)的关系为w=(relation[x]+(d-1))%3(其中(d-1)为y与x的关系,可以把x当作y的父节点推出来) 
            find(y)与find(x)的关系要用路径压缩算法反着推出来 relation[find(y)]=(w-relation[y]+3)%3 
            
Part III - 判断
        如果 find(x)==find(y)代表以前确立了关系,(d-1)表示y与x的关系
        relation[y]是y与根关系,(3-relation[x])%3是根与x关系
        如果(relation[y]-relation[x]+3)%3!=d-1则为假话 

******************************************************************/
#include<cstdio>
#define maxn 50000
int f[maxn],relation[maxn];
int find(int x){
    if(f[x]==x)return x;
    find(f[x]);
    relation[x]+=relation[f[x]];relation[x]%=3;
    return f[x]=f[f[x]];
}
int mo(int x){
    return x>=0?x%3:(x%3)+3;
}
int main(){
    freopen("eat.in","r",stdin);
    freopen("eat.out","w",stdout);
    int n,ans=0,k,d,x,y,a,b;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        f[i]=i;
    }
    for(int i=0;i<k;i++){
        scanf("%d%d%d",&d,&x,&y);d--;
        if(x>n||y>n){
            ans++;
            continue;
        }
        a=find(x),b=find(y);
        if(a==b){
            if(mo(relation[y]-relation[x])!=d)ans++;
        }
        else{
            relation[b]=mo(relation[x]-relation[y]+d);
            f[b]=a;
        }
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2017-08-14 11:48  Bennettz  阅读(149)  评论(0编辑  收藏  举报