经典经典并查集!!!!
强烈建议自己写一遍,真是。。
其实重点就是偏移量的更新。ps可以用向量解。
传送传送戳
推荐并查集讲得很好玩的戳
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,k,i,num,r1,r2,d,x,y;
/*relaton = 0,同类;
relation=1,被父节点吃;
relationg=2,吃父节点;*/
struct node
{
int parent;
int relation;
}p[50010];
int find(int x)
{
int t;
if(p[x].parent==x) return x;
else
{
t=p[x].parent;
p[x].parent=find(t);
p[x].relation=(p[t].relation+p[x].relation)%3;
}
return p[x].parent;
/*说明:
在查找之前,x的父亲节点是fx;假设p[x].relation=0(即r和父亲同类),
p[x].relation=1(也就是fx被fxx吃;经过路径压缩,r的父亲节点变为fxx;
所以更新关系应该为up;*/
}
void join()
{
p[r1].parent=r2;
p[r1].relation=(3+d-1+p[y].relation-p[x].relation)%3;
/*if p[x].relation=0 p[y].relation=1(即rooty吃y),则有:\
1>输入d=1时,可以推出rooty吃rootx,
即p[rooty].relation=2;
2>输入d=2时,即输入的x吃y,可以推出rooty与rootx是同类(因为rooty吃y,x吃y,
则rooty与x是同类,又rootx与x是同类),即p[rooty].relation=0;
+3是为了判负数;*/
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)//初始化
{
p[i].parent=i;
p[i].relation=0;
}
num=0;
while(k--)
{
scanf("%d%d%d",&d,&x,&y);
if(x>n||y>n||(d==2&&x==y)) num++;
else
{
r1=find(x);
r2=find(y);
if(r1!=r2)
join();
else
{
if(d==1&&p[x].relation!=p[y].relation) num++;
else if(d==2&&(p[x].relation-p[y].relation+3)%3!=1) num++;
}
}
}
printf("%d\n",num);
return 0;
}