并查集,在一些有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;
}