http://poj.org/problem?id=1182

重点依旧是用rank记录相对于根节点的关系,并及时跟新rank的值。

code:

#include<cstdio>
using namespace std ;
int f[50001] ;
int r[50001] ;//与根节点的关系
int find_Set(int x){
    int temp ;
    if(x==f[x])
        return x ;
    temp = f[x] ;
    f[x] = find_Set(temp) ;
    r[x] = (r[temp]+r[x]) % 3 ;
    /*
        r[x]是相对于x原根节点temp的关系值,现在相对根节点已不是temp
        故更新r[x]值时要加上temp相对于其根节点的差值r[temp]
        递归调用,查找一次x可将在其前入集的点全部更新
    
*/
    return f[x] ;
}
void Union(int x, int y, int fx, int fy, int d){
    f[fy] = fx ;
    r[fy] = (d+2+r[x]-r[y]) % 3 ;
    /*
        r[]为此元素与根节点关系,1为被吃,2为吃
        find_set()后,如果x已经入集,则fx为根节点,若未入,则fx为其本身
        无论哪种情况r[fx],r[fy]均为0
        将fx作为根节点,则r[x]不变,因为r[fx]恒为0
        若x吃y,则r[y] = r[x]+1
        若为同类,则r[y] = r[x]+0
        列表可得出r[fy]的改变量
    
*/
}
int main(){
    int n, k, i, d, x, y, fail, fx, fy ;
    scanf("%d%d", &n, &k) ;
    fail = 0 ;
    for(i=0; i<=n; i++){
        f[i] = i ;
        r[i] = 0 ;
    }
    for(i=0; i<k; i++){
        scanf("%d%d%d", &d, &x, &y) ;
        if(x>n||y>n||(d==2&&x==y)){
            fail ++ ;
            //printf("%d %d\n", x, y) ;
            continue ;
        }
        fx = find_Set(x) ;
        fy = find_Set(y) ;
        if(fx!=fy)
            Union(x, y, fx, fy, d) ;
        else{
            if(d==1&&r[x]!=r[y]){//与root关系不同
                fail ++ ;
                //printf("%d %d\n", x, y) ;
            }
            if(d==2&&(r[x]-r[y]+3)%3!=2){//列举x吃y情况下r所有可能,得出结论
                fail ++ ;
                //printf("%d %d\n", x, y) ;
            }
        }
    }
    printf("%d\n", fail) ;
    return 0 ;


posted on 2012-02-01 00:30  追逐.  阅读(230)  评论(0编辑  收藏  举报