/*
初始化并查集的所有集合 和根节点直接的关系
找到父节点
合并集合,并更新点和父节点直接的关系
判断是否是真话
if 父节点不相等 true 加入集合中
if 相等
if() 判断在集合中与 根节点的关系对不对 对
true [加入集合]错 false
主函数:
创建集合
找到2点的父节点
判断是否是真话
假话 count++
真话 和并集合
*/
#include<stdio.h> #include<string.h> #define MAX 50005 int father[MAX]={0}; int rank[MAX]={0}; int k,n; void make_set() { int i; for(i=1;i<=n;i++) { father[i]=i;rank[i]=0;//父节点都是自己 和父节点的关系都是同类0 } } int find_father(int x)//只找到父节点 { if(father[x]==x) return x; int lao=father[x];//更新原来集合下所有点的根节点 和 关系值 father[x]= find_father(father[x]); rank[x]=(rank[x]+rank[lao])%3; return father[x]; } void union_set(int r,int x,int y) { int fx,fy; //先将x和y的根节点找到 fx=find_father(x); fy=find_father(y); if(fx==fy) return ; father[fx]=fy;//将x的集合加到y的集合下面 rank[fx]=(rank[y]+r-rank[x]+3)%3;//+3防止出现负的情况 通过向量可以确定关系 } int isTrue(int r,int x,int y) { int fx,fy; if(x>n || y>n || ((x==y)&&((r+1)==2)) ) return 0; //先将x和y的根节点找到 fx=find_father(x); fy=find_father(y); if(fx!=fy)//证明原先的集合中没有他们之间的关系 可以加入到集合中 return 1; else { if(rank[x]==((rank[y]+r)%3))//如果x-y的关系正确 return 1; else return 0; } } int main(void) { int i,r,x,y,fx,fy,count=0; scanf("%d%d",&n,&k); make_set(); for(i=1;i<=k;i++) { scanf("%d%d%d",&r,&x,&y); if(isTrue(r-1,x,y)) { union_set(r-1,x,y); } else { count++; } } printf("%d\n",count); return 0; }
原文:http://www.cnblogs.com/woshijishu3/p/3719604.html