// based on https://github.com/iwiwi/radix-heap #include #include #include #include #include #include #include #include #include namespace radix_heap { namespace internal { template class find_bucket_impl; template <> class find_bucket_impl { public: static inline constexpr size_t find_bucket(uint32_t x, uint32_t last) { return x == last ? 0 : 32 - __builtin_clz(x ^ last); } }; template <> class find_bucket_impl { public: static inline constexpr size_t find_bucket(uint64_t x, uint64_t last) { return x == last ? 0 : 64 - __builtin_clzll(x ^ last); } }; template inline constexpr size_t find_bucket(T x, T last) { return find_bucket_impl::find_bucket(x, last); } template class encoder_impl_integer; template class encoder_impl_integer { public: typedef KeyType key_type; typedef KeyType unsigned_key_type; inline static constexpr unsigned_key_type encode(key_type x) { return x; } inline static constexpr key_type decode(unsigned_key_type x) { return x; } }; template class encoder_impl_integer { public: typedef KeyType key_type; typedef typename std::make_unsigned::type unsigned_key_type; inline static constexpr unsigned_key_type encode(key_type x) { return static_cast(x) ^ (unsigned_key_type(1) << unsigned_key_type( std::numeric_limits::digits - 1)); } inline static constexpr key_type decode(unsigned_key_type x) { return static_cast( x ^ (unsigned_key_type(1) << (std::numeric_limits::digits - 1))); } }; template class encoder_impl_decimal { public: typedef KeyType key_type; typedef UnsignedKeyType unsigned_key_type; inline static constexpr unsigned_key_type encode(key_type x) { return raw_cast(x) ^ ((-(raw_cast(x) >> (std::numeric_limits::digits - 1))) | (unsigned_key_type(1) << (std::numeric_limits::digits - 1))); } inline static constexpr key_type decode(unsigned_key_type x) { return raw_cast( x ^ (((x >> (std::numeric_limits::digits - 1)) - 1) | (unsigned_key_type(1) << (std::numeric_limits::digits - 1)))); } private: template union raw_cast { public: constexpr raw_cast(T t) : t_(t) {} operator U() const { return u_; } private: T t_; U u_; }; }; template class encoder : public encoder_impl_integer::value> {}; template <> class encoder : public encoder_impl_decimal {}; template <> class encoder : public encoder_impl_decimal {}; } // namespace internal template > class pair_radix_heap { public: typedef KeyType key_type; typedef ValueType value_type; typedef EncoderType encoder_type; typedef typename encoder_type::unsigned_key_type unsigned_key_type; pair_radix_heap() : size_(0), last_(), buckets_() { buckets_min_.fill(std::numeric_limits::max()); } void push(key_type key, const value_type &value) { unsigned_key_type x = encoder_type::encode(key); if (last_ > x) { std::cerr << "PQ: not monotone: " << last_ << " vs " << x << std::endl; x = last_; } ++size_; const size_t k = internal::find_bucket(x, last_); buckets_[k].emplace_back(x, value); buckets_min_[k] = std::min(buckets_min_[k], x); } void push(key_type key, value_type &&value) { unsigned_key_type x = encoder_type::encode(key); if (last_ > x) { std::cerr << "PQ: not monotone: " << last_ << " vs " << x << std::endl; x = last_; } ++size_; const size_t k = internal::find_bucket(x, last_); buckets_[k].emplace_back(x, std::move(value)); buckets_min_[k] = std::min(buckets_min_[k], x); } template void emplace(key_type key, Args &&... args) { unsigned_key_type x = encoder_type::encode(key); if (last_ > x) x = last_; ++size_; const size_t k = internal::find_bucket(x, last_); buckets_[k].emplace_back(std::piecewise_construct, std::forward_as_tuple(x), std::forward_as_tuple(args...)); buckets_min_[k] = std::min(buckets_min_[k], x); } key_type topKey() { pull(); return encoder_type::decode(last_); } value_type &topVal() { pull(); return buckets_[0].back().second; } void pop() { pull(); buckets_[0].pop_back(); --size_; } size_t size() const { return size_; } bool empty() const { return size_ == 0; } void clear() { size_ = 0; last_ = key_type(); for (auto &b : buckets_) b.clear(); buckets_min_.fill(std::numeric_limits::max()); } void swap(pair_radix_heap &a) { std::swap(size_, a.size_); std::swap(last_, a.last_); buckets_.swap(a.buckets_); buckets_min_.swap(a.buckets_min_); } private: size_t size_; unsigned_key_type last_; std::array>, std::numeric_limits::digits + 1> buckets_; std::array::digits + 1> buckets_min_; void pull() { assert(size_ > 0); if (!buckets_[0].empty()) return; size_t i; for (i = 1; buckets_[i].empty(); ++i) ; last_ = buckets_min_[i]; for (size_t j = 0; j < buckets_[i].size(); ++j) { const unsigned_key_type x = buckets_[i][j].first; const size_t k = internal::find_bucket(x, last_); buckets_[k].emplace_back(std::move(buckets_[i][j])); buckets_min_[k] = std::min(buckets_min_[k], x); } buckets_[i].clear(); buckets_min_[i] = std::numeric_limits::max(); } }; } // namespace radix_heap