图的开始--第九天打卡之并查集(模板版)
作者:
lgd123
,
2021-08-02 10:45:40
,
所有人可见
,
阅读 252
/*并查集
1、对于并查集:处理不相交可合并的集合关系,叫做并查集。
2、并查集支持两个操作:合并、查询。
3、使用并查集的步骤:
①、初始化父节点集合p[],起初每一个 元素都是一个集合。
②、将两个元素合并:
对于合并:将两个元素所属的集合的祖宗节点通过find()找出来,将其中一个的祖宗节点,加到另一个的集合里,代表着两个集合的合并。
③、查询操作:
对于查询:两个元素的祖宗节点若是一个节点,那么这两个节点属于同一个节点。
4、对于路径压缩:
问题:如果一个节点是通过类似链表的链才访问到的祖宗节点,这样每次去比较该点和其他点的关系时,效率非常低。
设想:如果把每次访问后的结果以一种记录的方式,储存起来,每次再查询的时候可以直接使用。
解决:在查询每一个节点的同时,将所有访问到的节点的父节点都设为祖宗节点,这样下次从同一个节点找祖宗节点时,经过的节点数就会大大减少
*/
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int p[N];
//find()用于查找父节点,这里用到了路径压缩,如果找到祖宗节点,则直接返回祖宗节点,只查询一遍即可。
int find(int x)
{
if(p[x]!=x) p[x] = find(p[x]);
return p[x];
}
int main()
{
int n,m,a,b;
scanf("%d %d",&n,&m);
//初始化,一开始每一个元素都是一个集合。
for(int i = 1 ;i <= n ; i ++)
{
p[i]=i;
}
while(m--)
{
char op[2];
scanf("%s %d %d",op,&a,&b);
if(op[0]=='M') p[find(a)]=find(b);//合并集合
else{
if(find(a)==find(b)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}