并查集-种类并查集
题目大意
动物王国中有三类动物
A
,
B
,
C
A,B,C
A,B,C,一共有
n
n
n个动物和
m
m
m条信息
要求判断这
m
m
m条信息里有多少条信息是假的
这题是比较经典的种类并查集题,对于本题,我们需要开 3 × n 3\times n 3×n大小的并查集维护每个动物为以上三类的情况
对于每个动物 x x x,在 A , B , C A,B,C A,B,C类中的情况分别用 x , x + n , x + n + n x,x+n,x+n+n x,x+n,x+n+n表示
对于操作 1 1 1(合并同类):
若
x
,
y
x,y
x,y 已经给出过了互吃的关系,假话!
否则,合并
(
x
,
y
)
(x,y)
(x,y),
(
x
+
n
,
y
+
n
)
(x+n,y+n)
(x+n,y+n),
(
x
+
n
+
n
,
y
+
n
+
n
)
(x+n+n,y+n+n)
(x+n+n,y+n+n)
对于操作 2 2 2 ( x x x 吃 y y y):
若已经有了
y
y
y 吃
x
x
x 的关系或者已经
x
,
y
x,y
x,y 已经为同类,假话!
否则合并
(
x
,
y
+
n
)
(x,y+n)
(x,y+n),
(
x
+
n
,
y
+
n
+
n
)
(x+n,y+n+n)
(x+n,y+n+n),
(
x
+
n
+
n
,
y
)
(x+n+n,y)
(x+n+n,y)
代码:
#include<cstdio>
#include<iostream>
using namespace std;
const int Maxn=150000+23,inf=0x3f3f3f3f;
int f[Maxn],n,m,ans;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
int find(int x)
{
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
inline void uni(int x,int y)
{
f[find(x)]=find(y);
}
int main()
{
//freopen("in.txt","r",stdin);
n=read(),m=read();
for(int i=1;i<=n*3;++i)
f[i]=i;
for(int i=1;i<=m;++i)
{
int opt=read(),x=read(),y=read();
if(x>n ||y>n || x==y && opt==2){ans++;continue;}
if(opt==1)
{
if(find(x)==find(y+n) || find(x+n)==find(y))
{ans++;continue;}
uni(x,y);
uni(x+n,y+n);
uni(x+n+n,y+n+n);
}
else
{
if(find(x)==find(y) || find(y)==find(x+n))
{ans++;continue;}
uni(x,y+n);
uni(x+n,y+n+n);
uni(x+n+n,y);
}
}
printf("%d\n",ans);
return 0;
}