並查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查找一個元素在哪個集合中。這一類問題近幾年來反覆出現在信息學的國際國內賽題中,其特點是看似並不複雜,但數據量極大,若用正常的數據結構來描述的話,往往在空間上過大,計算機無法承受;即使在空間上勉強通過,運行的時間複雜度也極高,根本就不可能在比賽規定的運行時間(1~3秒)內計算出試題需要的結果,只能用並查集來描述。(摘自百度)
並查集其實就是找到自己的老大,形成各自的幫派↓
那我們先定義f[i]表示第 i 個人的老大是誰
int Find(int x){
if(f[x] == x) return x;//像歐陽鋒和韋小寶一樣,自己做自己的老大[表情]
return Find(f[x]);
}
然後是路徑壓縮:這時,因爲我們要路過他所有的上級,我們也可以順便使途中經過的人的大哥也變成老大。
inline int Find(int x){
return x == f[x] ? x : (f[x] = find(f[x]));
// if (x == f[x]) return x;
// return f[x] = Find(f[x]);
}
路徑壓縮的代碼,看得懂很好,看不懂可以自己手動模擬一下,其實敲很簡單的。
大概的意思↓
模板題目👈點這
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N = 1000000 + 1;
int f[N];
inline int Find(int x){
return x == f[x] ? x : (f[x] = find(f[x]));
// if (x == f[x]) return x;
// return f[x] = Find(f[x]);
}
inline void unit(int x, int y){
x = Find(x);
y = Find(y);
if (x != y) f[x] = y;
}
int n , m;
signed main(){
scanf("%d%d", &n, &m);
for(re int i = 1;i <= n; i++) f[i] = i;
for(re int i = 1;i <= m; i++){
int x, y, z;
scanf("%d", &z);
if(z == 1){
scanf("%d%d", &x, &y);
unit(x, y);
}
else if(z == 2){
scanf("%d%d", &x, &y);
if(Find(x) == Find(y)) printf("Y\n");
else printf("N\n");
}
}
return 0;
}