合并集合(并查集)
并查集
并查集可以快速实现( 时间复杂度近乎 O(1) ):
1.将两个集合合并
2.判断两个元素是否在一个集合中
基本原理:每个集合用一棵树来表示,树根的编号就是这个集合的编号,每个节点存储自身的父节点,用p[x]表示 x 节点的父节点,当p[x]= x时,表示这个结点为根节点。在进行合并操作时,只需要把其中一棵树变成另一棵树的子树即可,即两个树根节点分别是 p[x] =x 和 p[y] =y; 我们只需要将 p[y] =x 即可。
路径压缩优化:在进行结点查找根节点的操作后,直接把这个这个结点的路径上的所有结点的父节点直接指向根节点,下次再查询这些结点时时间复杂度就变成O(1)了。
例题:
输入样例:
4 5 M 1 2 M 3 4 Q 1 2 Q 1 3 Q 3 4
预期输出:
Yes
No
Yes
代码实现:
#include<bits/stdc++.h>
using namespace std;
const int N =1e5+10;
int p[N];
int find (int x )
{
if (p[x] != x ) p[x] =find(p[x]); //路径压缩优化,将该路径上的每个结点的父节点都直接指向根节点。下次查询的时候时间复杂度可以优化到O(1)
return p[x];
}
int main()
{
for(int i =0;i<N;i++) p[i]=i;
int n,m;
bool flag ;
cin>>n>>m;
while(m--)
{
char op[2];
int a,b;
scanf("%s%d%d",op,&a,&b);
if(op[0] == 'M') p[find(a)] = find(b);//合并:让其中一个结点所在的树变成另一个结点的子树
else
{
if(find(a) == find(b)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
}

浙公网安备 33010602011771号