题解
题目要求我们判假,如果我们用并查集来做这道题,应该何从下手呢?首先,很显然的是,我们必须维护一个点与点关系的集合,通过这个关系集合来判假。原始的并查集只能用于维护“属于同一类“的这种关系,但是这道题却还要求我们维护吃的关系,这样才能针对每一个给出的论断进行判断。维护属于同一组的这种信息很容易实现,但是又如何体现捕食的关系呢?稍加思考,可以这样来转化。针对每只动物,为他们分别创建三个元素,每个元素表示不同的种类信息(具体实现为i表示这只动物是A,i+N就表示是B,i+2*N就表示这只动物是C了),这样,就用N*3个元素来建立并查集,这样,种类信息便成功加进来了。再来,就是维护了。其实很简单,虽然不知道给出的每一个论断(这里指第二种)中,两只动物分别是什么种类的,但事实上无需知道,因为食物链是一个环,随便哪一点选作A都行,只要每种动物的相对关系不变就行。所以,我们把同一个集合中的所有元素都看做符合事实,由于加上了类型信息,所以吃的关系也能判断出来。如此一来,针对每一个论断直接判断是否矛盾,不矛盾,就更新集合,否则是假话,把计数变量加一就可以了。下面是具体的实现代码。
#include <cstdio>
#define maxn 200000+10
int father[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
father[i]=i;
}
int find(int x)
{
if(x!=father[x]) father[x]=find(father[x]);
return father[x];
}
void Union(int x,int y)
{
x=find(x); y=find(y); father[x]=y;
}
bool same(int x,int y)
{
return find(x)==find(y);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
init(n*3);
int ans=0;
for(int i=0;i<k;i++)
{
int d,x,y;
scanf("%d%d%d",&d,&x,&y);
if(x>n || y>n)
{
ans++;continue;
}
if(d==1)
{
if(same(x,y+n) || same(x,y+n*2))
{
ans++;
}
else
{
Union(x,y);
Union(x+n,y+n);
Union(x+n*2,y+n*2);
}
}
else
{
if(same(x,y) || same(x,y+n*2))
{
ans++;
}
else
{
Union(x,y+n);
Union(x+n,y+n*2);
Union(x+n*2,y);
}
}
}
printf("%d",ans);
return 0;
}