poj1182 带权并查集

来源:互联网 发布:广西公务员网络考试 编辑:程序博客网 时间:2024/06/07 20:51
/** * poj1182 带权并查集 * 运用并查集进行分类、合并的操作,最开始大家都是自己为一个集合,随着小集合逐渐结成,小集合向另一个集合合并时,就可以将吃和被吃的关系统一起来,找到统一的参照系 * 这就是带权并查集存在的意义 * 在unionset函数中,负责合并的时候,将被合并一个集合的根的类型进行相应翻转,而在getfather函数中,自上而下对该树枝进行了修正 */#include <cstdio>const int MAX_NUM = 50005;int n,k;struct animal{    int father;    char type;}a[MAX_NUM];int getfather(int x){    int oldfx = a[x].father;    if(oldfx == x){        return x;    }    else{        a[x].father = getfather(a[x].father);        a[x].type = (a[x].type + a[oldfx].type)%3;        return a[x].father;    }}void unionset(int r,int x,int y){    int fx = getfather(x),fy=getfather(y);    if(fx == fy){        return ;    }    else{        a[fy].father = fx;        //如果原来的y吃自己祖先,x吃自己祖先,现在fy归类在fx下面,就要和x一致,所以+a[x].type        //-a[y].type是为了获得自己,即fy的状态        //r反映的是x 与 y之间的关系,现在就要反过来,所以要-(r-1)        a[fy].type = (1 - r + a[x].type - a[y].type + 6) % 3;//fy下面的状态在getfather函数内进行转换    }}bool istrue(int relation,int x,int y){    if(x > n || y > n || ( (x == y) && (relation==2)) ){        return false;    }    else{        if(getfather(x)!=getfather(y)){            return true;        }        else{            if(a[x].type == ((relation - 1 + a[y].type)%3) ){                return true;            }            else{                return false;            }        }    }}int main(){    int relation,x,y,lies=0;    scanf("%d%d",&n,&k);    for(int i=1;i<=n;++i){        a[i].father = i;        a[i].type = 0;    }    while(k--){        scanf("%d%d%d",&relation,&x,&y);        if(!istrue(relation,x,y)){            ++lies;        }        else{            unionset(relation,x,y);        }    }    printf("%d\n",lies);    return 0;}


0 0
原创粉丝点击