POJ 1182

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

 

你可能感兴趣的:(poj)