并查集
并查集可以快速实现( 时间复杂度近乎 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;}}
}
