cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
pairing_heap.hpp
1#pragma once
2
3#include <functional>
4#include <string>
5#include <vector>
6
7namespace cplib {
8
9namespace impl {
10
11// Left-child right-sibling representation of the pairing heap
12template <typename T>
13struct PairingHeapNode {
14 PairingHeapNode(const T& val) : _val(val), left(nullptr), right(nullptr), parent(nullptr) {}
15
16 PairingHeapNode(T&& val) : _val(std::move(val)), left(nullptr), right(nullptr), parent(nullptr) {}
17
18 template <typename... Args, typename = decltype(T(std::declval<Args>()...))>
19 PairingHeapNode(Args&&... args) : _val(std::forward<Args>(args)...), left(nullptr), right(nullptr), parent(nullptr) {}
20
21 // Add `child` as the youngest child (first in the sibling list). Both `this` and `child` must be root nodes.
22 void adopt(PairingHeapNode* child) {
23 if (!child) {
24 return;
25 }
26 child->right = left;
27 if (left) {
28 left->parent = child;
29 }
30 left = child;
31 child->parent = this;
32 }
33
34 // Deatch this node and its subtree from its parent, so that it becomes an independent root node.
35 // Must only be called on non-root nodes.
36 void detach() {
37 if (parent->left == this) {
38 parent->left = right;
39 } else {
40 parent->right = right;
41 }
42 if (right) {
43 right->parent = parent;
44 }
45 right = nullptr;
46 parent = nullptr;
47 }
48
49 T _val;
50 PairingHeapNode *left, *right, *parent;
51};
52
53} // namespace impl
54
70template <typename T, typename Comp = std::less<T>>
72 public:
73 using size_type = std::size_t;
74 using node_type = impl::PairingHeapNode<T>;
75
76 PairingHeap() : root(nullptr), _size(0), comp() {}
77
78 struct iterator {
79 const T& operator*() { return node->_val; }
80
81 const T* operator->() { return &node->_val; }
82
83 bool operator==(const iterator& rhs) const { return node == rhs.node; }
84
85 bool operator!=(const iterator& rhs) const { return node != rhs.node; }
86
87 private:
88 friend PairingHeap;
89 node_type* node;
90
91 iterator(node_type* node) : node(node) {}
92 };
93
95 size_type size() const { return _size; }
96
98 bool empty() const { return !root; }
99
101 const T& top() { return root->_val; }
102
104 iterator begin() { return iterator(root); }
105
107 iterator end() { return iterator(nullptr); }
108
114 iterator push(const T& t) {
115 auto node = new node_type(t);
116 _merge_with(node, 1);
117 return iterator(node);
118 }
119
121 iterator push(T&& t) {
122 auto node = new node_type(std::move(t));
123 _merge_with(node, 1);
124 return iterator(node);
125 }
126
129 template <typename... Args>
130 iterator emplace(Args&&... args) {
131 auto node = new node_type(std::forward<Args>(args)...);
132 _merge_with(node, 1);
133 return iterator(node);
134 }
135
142 void pop() {
143 _size--;
144 if (!root->left) {
145 delete root;
146 root = nullptr;
147 return;
148 }
149 auto* curr = root->left;
150 node_type* last = nullptr;
151 delete root;
152 // Merge in pairs, following the forward (`right`) linked list, and creating a backward (`parent`) linked list
153 while (true) {
154 auto next = curr->right;
155 if (!next) {
156 curr->parent = last;
157 last = curr;
158 break;
159 }
160 auto next_next = next->right;
161 curr->parent = nullptr;
162 curr->right = nullptr;
163 next->parent = nullptr;
164 next->right = nullptr;
165 auto merged = _merge_node(curr, next);
166 merged->parent = last;
167 last = merged;
168 if (!next_next) {
169 break;
170 }
171 curr = next_next;
172 }
173 // Merge from the back, following the backward (`parent`) linked list just created.
174 auto prev = last->parent;
175 while (prev) {
176 auto prev_prev = prev->parent;
177 last->parent = nullptr;
178 prev->parent = nullptr;
179 last = _merge_node(last, prev);
180 last->parent = prev_prev;
181 prev = prev_prev;
182 }
183 root = last;
184 }
185
192 void merge(PairingHeap&& other) {
193 _merge_with(other.root, other.size());
194 other._size = 0;
195 other.root = nullptr;
196 }
197
204 void decrease_key(iterator it, const T& new_key) {
205 if (it.node != root) {
206 it.node->detach();
207 it.node->_val = new_key;
208 _merge_with(it.node, 0);
209 } else {
210 root->_val = new_key;
211 }
212 }
213
220 void erase(iterator it) {
221 if (it.node != root) {
222 it.node->detach();
223 it.node->adopt(root);
224 root = it.node;
225 }
226 pop();
227 }
228
229 private:
230 node_type* root;
231 size_type _size;
232 Comp comp;
233
234 node_type* _merge_node(node_type* node1, node_type* node2) {
235 if (!node1) {
236 return node2;
237 } else if (!node2) {
238 return node1;
239 }
240 if (comp(node1->_val, node2->_val)) {
241 std::swap(node1, node2);
242 }
243 node2->adopt(node1);
244 return node2;
245 }
246
247 void _merge_with(node_type* other, size_type size_incr) {
248 root = _merge_node(root, other);
249 _size += size_incr;
250 }
251};
252
253} // namespace cplib
Definition: pairing_heap.hpp:78
Pairing heap, a pointer-based heap supporting efficient merge and decrease-key.
Definition: pairing_heap.hpp:71
size_type size() const
Returns the number of elements.
Definition: pairing_heap.hpp:95
iterator begin()
Returns an iterator to the top element, or a null-pointer iterator if the heap is empty.
Definition: pairing_heap.hpp:104
iterator push(T &&t)
Insert an element into the heap.
Definition: pairing_heap.hpp:121
void erase(iterator it)
Remove an arbitrary element from the heap.
Definition: pairing_heap.hpp:220
void pop()
Remove the top element from the heap.
Definition: pairing_heap.hpp:142
void merge(PairingHeap &&other)
Merge this heap with another heap.
Definition: pairing_heap.hpp:192
iterator push(const T &t)
Insert an element into the heap.
Definition: pairing_heap.hpp:114
const T & top()
Returns the top element. The heap must be non-empty.
Definition: pairing_heap.hpp:101
bool empty() const
Returns whether the heap is empty.
Definition: pairing_heap.hpp:98
void decrease_key(iterator it, const T &new_key)
Decrease the value of a given element.
Definition: pairing_heap.hpp:204
iterator emplace(Args &&... args)
Construct a new element in place in the heap.
Definition: pairing_heap.hpp:130
iterator end()
Returns a null-pointer iterator, intended for default value or edge case checking.
Definition: pairing_heap.hpp:107