题目传送门
一道小根堆模板题……
在做这道题之前,我们先介绍一下小根堆是什么。
我们定义小根堆是一种对于任何一个父结点的权值总是小于或等于子节点权值的完全二叉树。因此,不难看出,一个小根堆的堆顶(这棵树的根节点)应该是这个堆(树)中权值最小的结点。
简单介绍完了小根堆,我们再介绍下如何存储。
存储
我们考虑用一个数组进行存储,用一个变量来记录堆里的元素个数。
1 2
| int heap[1000005]; int cnt;
|
学会了如何存储小根堆,接下来我们要实现几个操作:
插入一个数
我们需要在最后一个位置插入,然后从下往上进行维护。如果发现父结点的权值大于子结点的权值,则将子结点与父结点进行交换,然后继续往上进行搜索。
1 2 3 4 5 6 7 8 9 10 11
| void xds(int cur) { int fa = (cur - 1) / 2; if (heap[fa] > heap[cur]) { swap(heap[fa], heap[cur]); xds(fa); } } void insert(int x) { heap[cnt] = x; xds(cnt++); }
|
查询堆顶
之前说过,堆顶应该是整个堆中最小的元素,而我们插入维护是从下往上进行维护(对于整个数组,我们可以说是从后往前进行维护)的,因此堆顶为 heap[0]
。
删除堆顶
我们可以将堆顶与最后一个元素进行互换,然后将长度减 1,就相当于删掉了这个元素。之后我们从上往下维护一遍,我们分成没有子结点,有一个子结点,有两个子结点这 3 种情况进行维护,原理与插入差不多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void sdx(int cur) { if (2 * cur + 1 >= cnt) return ; if (2 * cur + 2 >= cnt) { if (heap[2 * cur + 1] < heap[cur]) swap(heap[2 * cur + 1], heap[cur]); return ; } int l = 2 * cur + 1, r = l + 1; if (heap[l] > heap[r]) swap(l, r); if (heap[l] < heap[cur]) { swap(heap[l], heap[cur]); sdx(l); } } void del() { swap(heap[0], heap[--cnt]); sdx(0); }
|
Code
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
| #include <bits/stdc++.h> #define ll long long #define INF 1e9 using namespace std; int n; int heap[1000005]; int cnt; void xds(int cur) { int fa = (cur - 1) / 2; if (heap[fa] > heap[cur]) { swap(heap[fa], heap[cur]); xds(fa); } } void insert(int x) { heap[cnt] = x; xds(cnt++); } void sdx(int cur) { if (2 * cur + 1 >= cnt) return ; if (2 * cur + 2 >= cnt) { if (heap[2 * cur + 1] < heap[cur]) swap(heap[2 * cur + 1], heap[cur]); return ; } int l = 2 * cur + 1, r = l + 1; if (heap[l] > heap[r]) swap(l, r); if (heap[l] < heap[cur]) { swap(heap[l], heap[cur]); sdx(l); } } void del() { swap(heap[0], heap[--cnt]); sdx(0); } signed main() { ios :: sync_with_stdio(0); cin >> n; for (int i = 1; i <= n; i++) { int op; cin >> op; if (op == 1) { int x; cin >> x; insert(x); } else if (op == 2) cout << heap[0] << "\n"; else del(); } return 0; }
|