poj 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 ;


你可能感兴趣的:(poj)