POJ 1182

食物链:

网上看的别人的加过注释的代码,对于rank的解释很好,就摘录了

#include<iostream>
using namespace std;
const int Max = 50005;
 
int n, pa[Max], rank[Max];
 
void make_set(){
    for(int x = 1; x <= n; x ++){
        pa[x] = x;
        rank[x] = 0;   //  开始时集合的根也是x,属于同种类型,故类型差值为0。
    }
}
 
int find_set(int x){
    int tmp = pa[x];
    if(x != pa[x]){
        pa[x] = find_set(pa[x]);
        rank[x] = (rank[x] + rank[tmp]) % 3;
        //rank[x]是x相对原来的根元素tmp(前根节点)的差值,现在的根元素已不是tmp。
        //故要加上tmp对于现在的根元素的类型差值,rank[tmp]为tmp对于现在根元素类型的差值。
    }
    return pa[x];
}
 
void union_set(int x, int y, int w){
    int a = find_set(x);
    int b = find_set(y);
    pa[b] = a;
    rank[b] = (rank[x] - rank[y] + w + 3) % 3;
    //这个公式可用列表推出,列表时必须保证rank[x]不变,由于根节点的rank[a]总为0。
    //然后如果x吃y,则rank[y] = rank[x] + 1,然后可推出rank[b]的改变量。x与y同类也运用这个思路。
}
 
int main(){
    int t, ans = 0;
    scanf("%d %d", &n, &t);
    make_set();
    while(t --){
        int d, x, y;
        scanf("%d %d %d", &d, &x, &y);
        if(x > n || y > n) ans ++;   //  当前的话中X或Y比N大,就是假话。 
        else{
            if(d == 1){
                if(find_set(x) == find_set(y) && rank[x] != rank[y]) ans ++;
                else union_set(x, y, 0);
            }
            if(d == 2){
                if(find_set(x) == find_set(y) && (rank[x]+1) % 3 != rank[y]) ans ++;
                else union_set(x, y, 1);
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}


你可能感兴趣的:(POJ 1182)