启发式合并指的是,对于两个集合 \(x\) 和 \(y\) 合并的操作,每次把元素个数更少的集合合并到元素个数更大的集合内,即:设 \(x\) 为元素更少的集合,那么就把 \(x\) 合并到 \(y\) 内。
并查集的按秩合并就是用的启发式合并
对于并查集来说这种合并是为了减小深度以节约时间
来一道例题
P3201 [HNOI2009] 梦幻布丁
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int n, m, ans;
int c[N], fa[N], h[N], st[N], siz[N], nxt[N];
void merge(int x, int y) {
for (int i = h[x]; i; i = nxt[i]) {
ans -= (c[i - 1] == y) + (c[i + 1] == y);
}
for (int i = h[x]; i; i = nxt[i]) {
c[i] = y;
}
nxt[st[x]] = h[y], h[y] = h[x], siz[y] += siz[x];
h[x] = st[x] = siz[x] = 0;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i) {
scanf("%d", &c[i]);
fa[c[i]] = c[i];
ans += (c[i] != c[i - 1]);
if (!h[c[i]]) {
st[c[i]] = i; // 设定开始位置
}
++ siz[c[i]], nxt[i] = h[c[i]], h[c[i]] = i;
}
while (m --) {
int op;
scanf("%d", &op);
if (op == 2) {
printf("%d\n", ans);
}
else {
int x, y;
scanf("%d%d", &x, &y);
if (x == y) continue;
if (siz[fa[x]] > siz[fa[y]]) {
swap(fa[x], fa[y]);
}
if (!siz[fa[x]]) continue;
merge(fa[x], fa[y]);
}
}
return 0;
}