/*
初始化并查集的所有集合 和根节点直接的关系
找到父节点
合并集合,并更新点和父节点直接的关系
判断是否是真话
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;
}
食物链(带全并查集)