【並查集】AcWing836. 合併集合 —— 並查集入門
阿新 • • 發佈:2022-05-18
並查集
處理問題
1.將兩個集合合併
2.詢問兩個集合是否在一個集合當中
暴力思維
1.詢問兩個元素是否在一個集合
belong[x] = a; //元素x在a集合
if(belong[x] == belong[y]) //判斷a與b是否在一個集合,複雜度O(1)
2.合併集合
//將a,b集合合併為c集合,時間複雜度O(n)
if(belong[x] == a) belong[x] = c;
if(belong[y] == b) belong[y] = c;
並查集可以在近乎O(1)複雜度完成以上兩個操作。
基本原理
每個集合用一棵樹來表示,樹根的編號就是整個集合的編號。每個結點儲存它的父節點,p[x]表示x的父節點。
問題1:如何判斷樹根:if(p[x] == x)
問題2:如何求x的集合編號:while(p[x] != x) x = p[x];
問題3:如何合併兩個集合:p[x]是x的集合編號,p[y]是y的集合編號,合併——p[x]=y
優化:路徑壓縮
當我們進行一次查詢後,將路途上的所有結點的父親改為根節點,下次查詢即可以O(1)查的根節點
AcWing836. 合併集合
題解
#include <iostream> #include <cstdio> using namespace std; const int N = 1e5 + 10; string s; int p[N], n, m, x, y; int find(int x) //查詢集合與路徑壓縮 { if(p[x] != x) return p[x] = find(p[x]); return x; } int main() { scanf("%d%d",&n, &m); for(int i = 1; i <= n; ++i) p[i] = i; while(m -- ) { cin >> s; scanf("%d%d", &x, &y); if(s == "M") p[find(x)] = find(y); //一定要用父節點合併這樣才能保證根節點唯一 else printf("%s\n", find(x) == find(y) ? "Yes":"No"); } return 0; }