启发式合并指的是,对于两个集合 \(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;
}