并查集
功能:
- 将两个集合合并
- 询问两个元素是否在一个集合当中
查询的时间复杂度近乎O(1)
基本原理:
每个集合用一棵树来表示。树根的编号就是整个集合的编号。每个节点储存它的父节点,p[x]表示x的父节点。
问题1:如何判断树根: if(p[x] == x)
问题2:如何求x的集合编号: while(p[x] != x) x = p[x];(常用优化方法:路径压缩)
问题3:如何合并两个集合: px是x的集合编号,py是y的集合编号。p[x] = y;
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1E5+10;
int p[N];
int find(int x)
{
if(p[x]!=x)
p[x]=find(p[x]); //路径压缩
return p[x];
}
int main()
{
int n,m;
cin>>n>>m;
//并查集初始化
for(int i=1;i<=n;i++)
p[i]=i;
while(m--)
{
char op[2];
int a,b;
cin>>op;
if(op[0]=='M')
{ //合并两个集合
cin>>a>>b;
p[find(a)]=p[find(b)];
}
else
{
cin>>a>>b;
if(find(a)==find(b))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
}
return 0;
}
并查集功能---计算子集大小
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int cnt[N];
int p[N];
int find(int x)
{
if(p[x]!=x)
p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
p[i]=i,cnt[i]=1;
while(m--)
{
string op;
int a,b;
cin>>op;
if(op=="C")
{
cin>>a>>b;
a=find(a),b=find(b);
if(a!=b)
{
//a成为b的子集
p[a]=b;
//b的子集扩大
cnt[b]+=cnt[a];
}
}
else if(op=="Q1")
{
cin>>a>>b;
if(find(a)==find(b))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
else if(op=="Q2")
{
cin>>a;
cout<<cnt[p[find(a)]]<<endl;
}
}
return 0;
}