是一道挺不错的并查集题目。不同于普通并查集的题,这道题不仅仅需要对一种情况进行分集合,而是对三种情况区分集合:两种动物同类,A吃B,B吃A。这样我们可以把数组开大三倍,a[i]表示第i个动物属于第1类动物这种情况,a[i+n]表示第i个动物属于第2类动物这种情况,a[i+2*n]表示第I个动物属于第3类动物这种情况。
当输入查询时,如果判断是正确的,就把可能发生的几种情况都放进同一个集合里面。例如,加入x和y是同类动物这个查询没有错误,那就把a[x]和a[y]、a[x+n]和a[y+n]、a[x+2*n]和a[y+2*n]分别放进同一个集合里。判断不正确就从反面进行查找。
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<list>
#include<string>
#include<map>
using namespace std;
#define maxn 50050
int father[maxn*3];
int find(int n)
{
if(n!=father[n]) father[n]=find(father[n]);
return father[n];
}
int main()
{
int n,k;
int sum=0;
int kind,x,y;
scanf("%d%d",&n,&k);
for(int i=0;i<=3*n;i++)
{
father[i]=i;
}
while(k--)
{
scanf("%d%d%d",&kind,&x,&y);
if(x>n||x<=0||y>n||y<=0)
{
sum++;
continue;
}
if(kind==1)
{
if(find(x)==find(y+n)||find(x)==find(y+2*n))
sum++;
else
{
father[find(x)]=find(y);
father[find(x+n)]=find(y+n);
father[find(x+2*n)]=find(y+2*n);
}
}
else if(kind==2)
{
if(find(x)==find(y)||find(x)==find(y+2*n)||find(x+2*n)==find(y+n))
sum++;
else
{
father[find(x)]=find(y+n);
father[find(x+n)]=find(y+2*n);
father[find(x+2*n)]=find(y);
}
}
}
printf("%d\n",sum);
return 0;
}