可以将并查集理解为一棵树
p[]表示祖宗节点,每一个点一开始的祖宗节点都是自己本身
如果要将两个数合并到一个集合中,则直接让一个数的祖宗节点变为另一个点
询问两个数是否在同一个集合中就只要查看他们的祖宗节点是否相同
#include <iostream>
using namespace std;
const int N = 100010;
int p[N];
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) p[i] = i;
while (m -- )
{
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);
if (*op == 'M') p[find(a)] = find(b);
else
{
if (find(a) == find(b)) puts("Yes");
else puts("No");
}
}
return 0;
}
连通块中点的数量
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],s[N],p[N];
int n,m;
int find(int x){//找祖宗
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
void hb(int a,int b){//合并连通块
int x=find(a);
int y=find(b);
p[x]=y;
s[y]+=s[x];
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){//初始化
p[i]=i;
s[i]=1;
}
int a,b;
string op;
while(m--){
cin>>op;
if(op=="C"){
cin>>a>>b;
if(a!=b&&find(a)!=find(b)) hb(a,b);
}
else if(op=="Q1"){
cin>>a>>b;
if(find(a)==find(b))cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
else{
cin>>a;
cout<<s[find(a)]<<endl;//size只有在祖宗节点才有意义
}
}
return 0;
}
食物链
思路
这里我们将同类域,捕食域,天敌域分别划分为x,x+n,x+n+n;
同类
如果x,y是同类,但是x的捕食域有y,那么错误
如果x,y是同类,但是x的天敌域有y,那么错误
天敌
如果x是y的天敌,但是x与y属于同类,那么错误
如果x是y的天敌,但是x的同类域中有y,那么错误
如果x是y的天敌,但是x的天敌域中有y,那么错误
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int p[N*3];
int ans;
int find(int x){
if(x!=p[x])p[x]=find(p[x]);
return p[x];
}
void hb(int a,int b){
p[find(a)]=find(b);
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n*3;i++)p[i]=i;
while(m--){
int op,x,y;
cin>>op>>x>>y;
if(x>n||y>n) ans++;//x或y超出范围
else if(op==1){
if(find(x+n)==find(y)||find(y+n)==find(x))ans++; //如果x,y是同类,但是x是y的捕食中的动物,或者x是y天敌中的动物,那么错误.
else {
hb(x,y);
hb(x+n,y+n);
hb(x+2*n,y+2*n);
}
}
else{
if(x==y||find(x+2*n)==find(y)||find(x)==find(y))ans++;//x就是y,或者他们是同类,再或者是y的同类中有x
else{
hb(x+n,y);//x的捕食域加入y
hb(x,y+n+n);//x加入y的天敌域
hb(x+n+n,y+n);//x的天敌域加入y的捕食域!!!
}
}
}
cout<<ans;
return 0;
}