很典型的并查集,我们只需要找到A,B,C类,然后我们必须保存他们之间的关系,这个关系我们使用3进制表示,同类(0),吃(2),被吃(2).然后我们就有一定的变换关系了。
rank[]//用来表示他与父节点的关系。
1 x y(x,y同类),x所在集合的根节点a,y所在的根节点b.(a!=b)
rank[x](x->a)==rank[y](y-->a)
rank[a](a->b)=rank[y](y->b)-rank[x](x->a);传递性
2 x y(x eat y)
rank[y](y->a)=rank[y](y->x)+rank[x](x->a),rank[y](y->x)=2;
so
rank[y](y->a)=2+rank[x](x->a);式1
rank[a](a->b)=rank[y](y->b)-rank[y](y->a);传递性 式2
由式1,2得
rank[a](a->b)=rank[y](y->b)-2-rank[x](x->a);
代码:
#include<stdio.h>
#define maxN 50001
struct{
int pre;
int rank;
}animal[maxN];
void init(int i)
{
animal[i].pre=-1;
animal[i].rank=0;//i节点与父节点的关系。0表示同类,2表示被吃,1表示吃。
}
int find(int i)
{
int t=animal[i].pre;
if(t<0)
return i;
animal[i].pre=find(t);
animal[i].rank=(animal[i].rank+animal[t].rank)%3;//路径压缩
return animal[i].pre;
}
int main()
{
int n,k,i,d,x,y;
int lie=0;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)
init(i);
for(i=0;i<k;i++)
{
scanf("%d%d%d",&d,&x,&y);
if((x>n||y>n)||(d==2&&x==y))
{
lie++;
continue;
}
int a=find(x);
int b=find(y);
if(d==1)//x,y同类
{
if(a==b)//如果x,y在一个集合.
{
if(animal[x].rank!=animal[y].rank)//如果x,y与根节点的关系不同,则表示x,y不在一个集合
lie++;
}
else//不在一个集合
{
animal[a].pre=b;//y所在的集合与x所在的集合合并,且根为b
animal[a].rank=(animal[y].rank-animal[x].rank+3)%3;//由于传递性
}
}
if(d==2)
{
if(a==b)
{
if(animal[x].rank!=(animal[y].rank+1)%3)//由于传递性
lie++;
}
else
{
animal[a].pre=b;
animal[a].rank=(animal[y].rank-animal[x].rank+4)%3;//传递性
}
}
}
printf("%d/n",lie);
return 0;
}