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

带权并查集第一题,三种类型的生物,分别加入三个集合,题解见注释

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
#define MAX_N 150005
int par[MAX_N] ;//父亲 
int rank[MAX_N] ;//树的高度 
void INIT(int n)
{
    for(int i=0 ;i<n ;i++){
        par[i]=i ;
        rank[i]=0 ;
    }
}
int find(int x)
{
    if(par[x]==x){
        return x ;
    }
    else{
        return par[x]=find(par[x]) ;
    }
}
void unite(int x,int y)
{
    x=find(x) ;
    y=find(y) ;
    if(x==y)return ;
    if(rank[x]<rank[y]){
        par[x]=y ;
    }
    else{
        par[y]=x ;
        if(rank[x]==rank[y])rank[x]++ ;
    }
}
bool same(int x,int y)
{
    return find(x)==find(y) ;
}
int n,k,T[100005],X[100005],Y[100005] ;
void solve()
{
    //x x+n x+2*n 分别代表A B C类 
    //x y属于同一类 合并x-A和y-A x-B和y-B x-C和y-C
    //x吃y 合并x-A和y-B x-B和y-C x-C和y-A 
    //提前判断矛盾 
    INIT(3*n) ;
    int ans=0 ;
    for(int i=0 ;i<k ;i++)
    {
        int t=T[i] ;
        int x=X[i]-1,y=Y[i]-1 ;
        if(x<0 || x>=n || y<0 || y>=n)
        {
            ans++ ;
            continue ;
        }
        if(t==1)
        {
            if(same(x,y+n) || same(x,y+2*n))
            {
                ans++ ;
            }
            else
            {
                unite(x,y) ;
                unite(x+n,y+n) ;
                unite(x+2*n,y+2*n) ;
            }
        }
        else
        {
            if(same(x,y) || same(x,y+2*n))
            {
                ans++ ;
            }
            else
            {
                unite(x,y+n) ;
                unite(x+n,y+2*n) ;
                unite(x+2*n,y) ;
            }
        }
    }
    printf("%d\n",ans) ;
}
int main()
{
    scanf("%d%d",&n,&k) ;
    for(int i=0 ;i<k ;i++)
        scanf("%d%d%d",&T[i],&X[i],&Y[i]) ;
    solve() ;
    return 0 ;
}
View Code

 常规带权并查集解法

#include <iostream>
#include <cstdio>
#include <set>
#include <cmath>
using namespace std ;
#define MAX_N 50005
int par[MAX_N] ;//父亲 
int rank[MAX_N] ;//树的高度 
void INIT(int n)
{
    for(int i=0 ;i<n ;i++){
        par[i]=i ;
        rank[i]=0 ;
    }
}
int find(int x)
{
    if(par[x]==x){
        return x ;
    }
    else{
        int temp=par[x] ;
        par[x]=find(par[x]) ;
        rank[x]=(rank[x]+rank[temp])%3 ;
        return par[x] ;
    }
}
void unite(int x,int y,int d)
{
    int xp=find(x) ;
    int yp=find(y) ;
    par[xp]=yp ;
    rank[xp]=(rank[y]-rank[x]+3+d)%3 ;
}
bool same(int x,int y)
{
    return find(x)==find(y) ;
}
int n,k,T[100005],X[100005],Y[100005] ;
void solve()
{
    INIT(n) ;
    int ans=0 ;
    for(int i=0 ;i<k ;i++)
    {
        int t=T[i] ;
        int x=X[i]-1,y=Y[i]-1 ;
        if(x<0 || x>=n || y<0 || y>=n)
        {
            ans++ ;
            continue ;
        }
        int xp=find(x) ;
        int yp=find(y) ;
        if(xp==yp)
        {
            if((rank[x]-rank[y]+3)%3!=t-1)
                ans++ ;          
        }
        else
        {
            unite(x,y,t-1) ;
        }
    }
    printf("%d\n",ans) ;
}
int main()
{
    scanf("%d%d",&n,&k) ;
    for(int i=0 ;i<k ;i++)
        scanf("%d%d%d",&T[i],&X[i],&Y[i]) ;
    solve() ;
    return 0 ;
}
View Code