Pixie
Loading...
Searching...
No Matches
segment_tree.h
1#pragma once
2
3#include <pixie/memory_usage.h>
4#include <pixie/rmq.h>
5
6#include <algorithm>
7#include <bit>
8#include <cstddef>
9#include <functional>
10#include <limits>
11#include <span>
12#include <stdexcept>
13#include <vector>
14
15namespace pixie::rmq {
16
28template <class T, class Compare = std::less<T>, class Index = std::size_t>
29class SegmentTree : public RmqBase<SegmentTree<T, Compare, Index>, T> {
30 public:
31 static constexpr std::size_t npos =
33 static constexpr Index invalid_index = std::numeric_limits<Index>::max();
34
38 SegmentTree() = default;
39
50 explicit SegmentTree(std::span<const T> values, Compare compare = Compare())
51 : values_(values), compare_(compare) {
52 build();
53 }
54
60 std::size_t size_impl() const { return values_.size(); }
61
68 T value_at_impl(std::size_t position) const { return values_[position]; }
69
80 std::size_t arg_min_impl(std::size_t left, std::size_t right) const {
81 if (left >= right || right > values_.size()) {
82 return npos;
83 }
84
85 left += leaf_base_;
86 right += leaf_base_;
87 std::size_t answer = npos;
88 while (left < right) {
89 if ((left & 1u) != 0) {
90 answer = better(answer, tree_[left]);
91 ++left;
92 }
93 if ((right & 1u) != 0) {
94 --right;
95 answer = better(answer, tree_[right]);
96 }
97 left >>= 1;
98 right >>= 1;
99 }
100 return answer;
101 }
102
109 std::size_t memory_usage_bytes_impl() const {
110 return sizeof(*this) + pixie::vector_capacity_bytes(tree_);
111 }
112
113 private:
125 std::size_t better(std::size_t left, std::size_t right) const {
126 if (left == npos || left == invalid_index) {
127 return right;
128 }
129 if (right == npos || right == invalid_index) {
130 return left;
131 }
132 if (compare_(values_[right], values_[left])) {
133 return right;
134 }
135 if (compare_(values_[left], values_[right])) {
136 return left;
137 }
138 return std::min(left, right);
139 }
140
151 Index build_better(Index left, Index right) const {
152 if (left == invalid_index) {
153 return right;
154 }
155 if (right == invalid_index) {
156 return left;
157 }
158 return compare_(values_[right], values_[left]) ? right : left;
159 }
160
170 void build() {
171 tree_.clear();
172 leaf_base_ = 0;
173 if (values_.empty()) {
174 return;
175 }
176 if (values_.size() > static_cast<std::size_t>(invalid_index)) {
177 throw std::length_error("RMQ segment tree index type is too small");
178 }
179
180 leaf_base_ = std::bit_ceil(values_.size());
181 tree_.clear();
182 tree_.resize(2 * leaf_base_);
183 for (std::size_t i = 0; i < values_.size(); ++i) {
184 tree_[leaf_base_ + i] = static_cast<Index>(i);
185 }
186 std::fill(tree_.begin() + leaf_base_ + values_.size(), tree_.end(),
187 invalid_index);
188 for (std::size_t node = leaf_base_; node > 1;) {
189 --node;
190 tree_[node] = build_better(tree_[node << 1], tree_[(node << 1) | 1]);
191 }
192 }
193
194 std::span<const T> values_;
195 Compare compare_;
196 std::size_t leaf_base_ = 0;
197 std::vector<Index> tree_;
198};
199
200} // namespace pixie::rmq
CRTP facade for static range-minimum-query indexes.
Definition rmq.h:28
SegmentTree()=default
Construct an empty segment tree.
T value_at_impl(std::size_t position) const
Return the value at an indexed position.
Definition segment_tree.h:68
std::size_t size_impl() const
Return the number of indexed values.
Definition segment_tree.h:60
SegmentTree(std::span< const T > values, Compare compare=Compare())
Build an iterative segment tree over values.
Definition segment_tree.h:50
std::size_t arg_min_impl(std::size_t left, std::size_t right) const
Return the first minimum position in [left, right).
Definition segment_tree.h:80
std::size_t memory_usage_bytes_impl() const
Return owned auxiliary memory usage in bytes.
Definition segment_tree.h:109
Definition rmq.h:15
Common interface for static range-minimum-query indexes.