食物链是一道经典的并查集的题目,蕴含了并查集最基本的查询与合并的方法。
首先,这是个中文题,题意自己理解。
从题意中可以了解到,要判断是不是假话有三种方法,第二、三种显而易见,一个if就可以解决问题。第一种就要用到并查集了(出现在前面的都是真话(还未有冲突),后面的与前面的有冲突就是假话)。
首先,什么是并查集呢,一个可以在O(1)时间内查询两者在不在一个集合内,或者合并两个集合。
根据这一道题,应该维护三个域(集合),就是一个动物的吃域,被吃域,和同类域。
(用并查集查询他们的所在域)如果x和y是同类(d==1)那么x的吃域和y的被吃域显然不能重合,如果不是同类,那么x的被吃域和y吃域显然不能重合(当然他们不能是同类),判定完了后,要将正确的域合并(并查集合并)。
(假话别忘了合并真的)
下面是代码。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int ma=50010;
int fa[3*ma],chi[ma],beichi[ma],tong[ma];//维护的域
int n,k;
int find(int x)//查询
{
if(fa[x]==x)
return x;
return fa[x]=find(fa[x]);
}
void get(int x,int y)
{
fa[find(x)]=find(y);//合并两个域
}
int ans;
int main()
{
cin>>n>>k;
for(int i=0;i<3*ma;i++)
{
fa[i]=i;
}
for(int i=0;i<ma;i++)
{
tong[i]=i;
chi[i]=i+ma;
beichi[i]=i+ma+ma;
}
for(int i=1;i<=k;i++)
{
int d,x,y;
scanf("%d%d%d",&d,&x,&y);
if((x==y&&d==2)||x>n||y>n)
{
ans++;
continue;
}
else//记住要先判定再合并,如果是假话就直接跳过了。
{
if(d==1)
{
if(find(beichi[x])==find(chi[y])||find(beichi[y])==find(chi[x]))//如果是同类的判定
{
ans++;
continue;
}
get(beichi[x],beichi[y]);//将正确的域合并
get(chi[x],chi[y]);
get(tong[x],tong[y]);
}
else
{
if(find(tong[x])==find(tong[y])||find(chi[y])==find(tong[x]))//如果是吃与被吃的关系的判定
{
ans++;
continue;
}
get(chi[x],tong[y]);//将正确的域合并
get(tong[x],beichi[y]);
get(beichi[x],chi[y]);
}
}
}
printf("%d\n",ans);
return 0;
}