-学习笔记-可并堆- 配对堆学习笔记

如果需要维护一个集合的最大值,那么我们可以直接用普通的堆来实现就行了。

但如果我们要维护多个集合的最大值,而且还要支持集合的合并操作,这时候就需要用可并堆来维护了。

为了方便说明,一下的操作都是以小根堆为基础进行。

可并堆有很多种,我选择了比较优秀的配对堆。

配对堆的核心操作就是合并。

那么该如何合并呢,比较两个堆的堆顶大小,大的合并到小的上面就行了。

其他常用的操作:

  • 插入操作:新建一个大小为一的堆,然后两个堆合并就行了。

  • 取最值操作:直接返回堆顶元素。

  • 弹出最值操作:如果堆顶有很多个儿子,我们该如何保证复杂度正确呢?将堆顶的儿子不断两两合并就行了。

由于弹出最值操作非常抽象,所以我画了个图:

最初是情况下是这样的:

然后经过下面两个步骤:

这样就保证了复杂度的正确性。

最后摆出个借鉴别人的配对堆模板代码(强行增加文章长度)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 1000010
struct Heap {
int v, id;
int s, xd;
}h[MAXN];
int fa[MAXN], a[MAXN];
bool ifd[MAXN];
int merge(int a, int b) {
if (h[a].v == 0) return b;
if (h[b].v == 0) return a;
if (h[a].v > h[b].v || (h[a].v == h[b].v && a > b)) std::swap(a, b);
h[b].xd = h[a].s;
h[a].s = b;
return a;
}
int merges(int a) {
if (h[a].v == 0 || h[h[a].xd].v == 0) return a;
int p = h[a].xd, q = h[p].xd;
h[a].xd = h[p].xd = 0;
return merge(merge(a, p), merges(q));
}
int del(int a) {
printf("%d\n", h[a].v);
h[a].v = -1;
return merges(h[a].s);
}
int find(int x) {
if (fa[x] == x) return x;
else return fa[x] = find(fa[x]);
}
bool un(int x, int y) {
if (x == y) return 0;
fa[y] = x;
return 1;
}
int head[MAXN], op, x, y, n, m;
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
fa[i] = i;
}
h[0].v = 0;
for (int i = 1; i <= n; i++) {
head[i] = i;
h[i].v = a[i];
h[i].id = i;
h[i].s = h[i].xd = 0;
}
while (m--) {
scanf("%d", &op);
if (op == 1) {
scanf("%d%d", &x, &y);
int _x = find(x), _y = find(y);
if (ifd[x] || ifd[y] || !un(_x, _y)) continue;
head[_x] = merge(head[_x], head[_y]);
}
else {
scanf("%d", &x);
if (ifd[x]) {
puts("-1");
continue;
}
int _x = find(x);
ifd[h[head[_x]].id] = 1;
head[_x] = del(head[_x]);
}
}
}
文章作者: RiverFun
文章链接: https://stevebraveman.github.io/blog/2019/11/07/109/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 RiverFun

评论
目录