简介

并查集是用来快速查询两个元素是否在同一个集合的数据结构。并查集有两个基本操作:集合合并,查询元素所在的集合。
时间复杂度的难点在于集合的合并,如果是线性数据结构的话,合并集合的复杂度至少要O(N)。
因此可以通过树形结构,集合的合并可以通过加一条边的方式,这样的话,合并的复杂度是O(1)。那么通过树形结构的查询操作是怎样的呢?查询操作可以通过查找树形结构根节点的序号代表集合的序号,如果两个树形结构的根节点是同一个,那么就直接判断出来了。
另外衍生出来的问题就是,查询操作的时间复杂度是树的高度,我们当然希望树的高度是1,因此如果再查询操作碰到树的高度超过1的,就把该路径所有的父节点指向最终的根节点。这种优化称为路径压缩。

代码

  1. #include <iostream>
  2. using namespace std;
  3. #define N 100010
  4. // 并查集查找 + 路径压缩
  5. int find(int *p, int x) {
  6. if(p[x] != x) {
  7. p[x] = find(p, p[x]);
  8. }
  9. return p[x];
  10. }
  11. int main() {
  12. int n, m;
  13. while(scanf("%d %d", &n, &m) != EOF) {
  14. int p[N];
  15. char c;
  16. int x, y;
  17. for (int i = 0; i < n; i ++) {
  18. p[i] = i;
  19. }
  20. for (int i = 0; i < m; i ++) {
  21. cin >> c;
  22. scanf("%d %d", &x, &y);
  23. // 合并操作
  24. if(c == 'M') {
  25. p[find(p, x)] = find(p, y);
  26. } else {
  27. // 查询操作
  28. if(find(p, x) == find(p, y)) {
  29. cout << "Yes" << endl;
  30. } else {
  31. cout << "No" << endl;
  32. }
  33. }
  34. }
  35. }
  36. return 0;
  37. }