This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub suisen-cp/cp-library-cpp
#include "library/datastructure/heap/binary_heap.hpp"
#ifndef SUISEN_BINARY_HEAP #define SUISEN_BINARY_HEAP #include <algorithm> #include <cassert> #include <functional> #include <type_traits> #include <utility> #include <vector> #include "library/datastructure/heap/heap_tag.hpp" namespace suisen { namespace internal::heap { template <typename T, typename Comp, typename HeapTag> struct BinaryHeap { using value_type = T; using compare_type = Comp; using heap_tag = HeapTag; static constexpr bool is_min_heap = heap_tag::is_min_heap; static constexpr bool is_max_heap = heap_tag::is_max_heap; BinaryHeap() = default; BinaryHeap(const Comp& comp) : _comp(comp) {} template <typename InputIterator> BinaryHeap(InputIterator first, InputIterator last) : _dat(first, last) { construct_heap(); } template <typename InputIterator> BinaryHeap(InputIterator first, InputIterator last, const Comp& comp) : _dat(first, last), _comp(comp) { construct_heap(); } template <typename Iterable, typename = std::void_t<typename Iterable::iterator>> BinaryHeap(const Iterable& dat) : BinaryHeap(dat.begin(), dat.end()) {} template <typename Iterable, typename = std::void_t<typename Iterable::iterator>> BinaryHeap(const Iterable& dat, Comp& comp) : BinaryHeap(dat.begin(), dat.end(), comp) {} void reserve(int capacity) { _dat.reserve(capacity); } bool empty() const { return _dat.empty(); } int size() const { return _dat.size(); } void clear() { _dat.clear(); } void shrink_to_fit() { _dat.shrink_to_fit(); } void push(const value_type& v) { _dat.push_back(v); heapify_up(_dat.size() - 1); } template <typename ...Args> void emplace(Args &&...args) { push(value_type(std::forward<Args>(args)...)); } const value_type& top() const { assert(_dat.size()); return _dat.front(); } value_type pop() { assert(_dat.size()); // std::pop_heap(_dat.begin(), _dat.end(), [this](const value_type &x, const value_type &y) { return compare(y, x); }); std::swap(_dat.front(), _dat.back()); value_type res = std::move(_dat.back()); _dat.pop_back(); heapify_down(0); return res; } const std::vector<value_type>& data() const { return _dat; } std::vector<value_type>& data() { return _dat; } // @brief O(n) void construct_heap() { const int m = _dat.size() >> 1; for (int i = m - 1; i >= 0; --i) heapify_down(i); } // for debug void check_heap_property() const { const int n = _dat.size(), m = n >> 1; for (int i = 0; i < m; ++i) { const int lch = 2 * i + 1, rch = 2 * i + 2; if (lch < n) assert(not compare(_dat[lch], _dat[i])); if (rch < n) assert(not compare(_dat[rch], _dat[i])); } } private: std::vector<value_type> _dat; compare_type _comp; void heapify_up(const int leaf, const int root = 0) { int cur = leaf; value_type val = std::move(_dat[cur]); while (cur != root) { int par = (cur - 1) >> 1; if (not compare(val, _dat[par])) break; _dat[std::exchange(cur, par)] = std::move(_dat[par]); } _dat[cur] = std::move(val); } void heapify_down(const int root) { const int n = _dat.size(), m = n >> 1; int cur = root; value_type val = std::move(_dat[cur]); while (cur < m) { int ch = (cur << 1) + 1; ch += ch + 1 < n and compare(_dat[ch + 1], _dat[ch]); if (not compare(_dat[ch], val)) break; _dat[cur] = std::move(_dat[ch]); cur = ch; } _dat[cur] = std::move(val); // heapify_up(cur, root); } bool compare(const T& lhs, const T& rhs) const { if constexpr (is_min_heap) { return _comp(lhs, rhs); } else { return _comp(rhs, lhs); } } }; } template < typename T, typename Comp = std::less<T>, std::enable_if_t<std::is_invocable_r_v<bool, Comp, T, T>, std::nullptr_t> = nullptr > using MinBinaryHeap = internal::heap::BinaryHeap<T, Comp, min_heap_tag>; template < typename T, typename Comp = std::less<T>, std::enable_if_t<std::is_invocable_r_v<bool, Comp, T, T>, std::nullptr_t> = nullptr > using MaxBinaryHeap = internal::heap::BinaryHeap<T, Comp, max_heap_tag>; } // namespace suisen #endif // SUISEN_BINARY_HEAP
#line 1 "library/datastructure/heap/binary_heap.hpp" #include <algorithm> #include <cassert> #include <functional> #include <type_traits> #include <utility> #include <vector> #line 1 "library/datastructure/heap/heap_tag.hpp" #line 5 "library/datastructure/heap/heap_tag.hpp" namespace suisen { namespace internal::heap { struct heap_tag_base {}; } struct min_heap_tag : internal::heap::heap_tag_base { static constexpr bool is_min_heap = true; static constexpr bool is_max_heap = false; }; struct max_heap_tag : internal::heap::heap_tag_base { static constexpr bool is_min_heap = false; static constexpr bool is_max_heap = true; }; template <typename T> struct is_heap_tag { static constexpr bool value = std::is_base_of_v<internal::heap::heap_tag_base, T>; }; template <typename T> constexpr bool is_heap_tag_v = is_heap_tag<T>::value; } // namespace suisen #line 12 "library/datastructure/heap/binary_heap.hpp" namespace suisen { namespace internal::heap { template <typename T, typename Comp, typename HeapTag> struct BinaryHeap { using value_type = T; using compare_type = Comp; using heap_tag = HeapTag; static constexpr bool is_min_heap = heap_tag::is_min_heap; static constexpr bool is_max_heap = heap_tag::is_max_heap; BinaryHeap() = default; BinaryHeap(const Comp& comp) : _comp(comp) {} template <typename InputIterator> BinaryHeap(InputIterator first, InputIterator last) : _dat(first, last) { construct_heap(); } template <typename InputIterator> BinaryHeap(InputIterator first, InputIterator last, const Comp& comp) : _dat(first, last), _comp(comp) { construct_heap(); } template <typename Iterable, typename = std::void_t<typename Iterable::iterator>> BinaryHeap(const Iterable& dat) : BinaryHeap(dat.begin(), dat.end()) {} template <typename Iterable, typename = std::void_t<typename Iterable::iterator>> BinaryHeap(const Iterable& dat, Comp& comp) : BinaryHeap(dat.begin(), dat.end(), comp) {} void reserve(int capacity) { _dat.reserve(capacity); } bool empty() const { return _dat.empty(); } int size() const { return _dat.size(); } void clear() { _dat.clear(); } void shrink_to_fit() { _dat.shrink_to_fit(); } void push(const value_type& v) { _dat.push_back(v); heapify_up(_dat.size() - 1); } template <typename ...Args> void emplace(Args &&...args) { push(value_type(std::forward<Args>(args)...)); } const value_type& top() const { assert(_dat.size()); return _dat.front(); } value_type pop() { assert(_dat.size()); // std::pop_heap(_dat.begin(), _dat.end(), [this](const value_type &x, const value_type &y) { return compare(y, x); }); std::swap(_dat.front(), _dat.back()); value_type res = std::move(_dat.back()); _dat.pop_back(); heapify_down(0); return res; } const std::vector<value_type>& data() const { return _dat; } std::vector<value_type>& data() { return _dat; } // @brief O(n) void construct_heap() { const int m = _dat.size() >> 1; for (int i = m - 1; i >= 0; --i) heapify_down(i); } // for debug void check_heap_property() const { const int n = _dat.size(), m = n >> 1; for (int i = 0; i < m; ++i) { const int lch = 2 * i + 1, rch = 2 * i + 2; if (lch < n) assert(not compare(_dat[lch], _dat[i])); if (rch < n) assert(not compare(_dat[rch], _dat[i])); } } private: std::vector<value_type> _dat; compare_type _comp; void heapify_up(const int leaf, const int root = 0) { int cur = leaf; value_type val = std::move(_dat[cur]); while (cur != root) { int par = (cur - 1) >> 1; if (not compare(val, _dat[par])) break; _dat[std::exchange(cur, par)] = std::move(_dat[par]); } _dat[cur] = std::move(val); } void heapify_down(const int root) { const int n = _dat.size(), m = n >> 1; int cur = root; value_type val = std::move(_dat[cur]); while (cur < m) { int ch = (cur << 1) + 1; ch += ch + 1 < n and compare(_dat[ch + 1], _dat[ch]); if (not compare(_dat[ch], val)) break; _dat[cur] = std::move(_dat[ch]); cur = ch; } _dat[cur] = std::move(val); // heapify_up(cur, root); } bool compare(const T& lhs, const T& rhs) const { if constexpr (is_min_heap) { return _comp(lhs, rhs); } else { return _comp(rhs, lhs); } } }; } template < typename T, typename Comp = std::less<T>, std::enable_if_t<std::is_invocable_r_v<bool, Comp, T, T>, std::nullptr_t> = nullptr > using MinBinaryHeap = internal::heap::BinaryHeap<T, Comp, min_heap_tag>; template < typename T, typename Comp = std::less<T>, std::enable_if_t<std::is_invocable_r_v<bool, Comp, T, T>, std::nullptr_t> = nullptr > using MaxBinaryHeap = internal::heap::BinaryHeap<T, Comp, max_heap_tag>; } // namespace suisen