39 :
public RmqBase<SparseTable<T, Compare, Index, Alignment>, T> {
41 static constexpr std::size_t npos =
43 static constexpr Index invalid_index = std::numeric_limits<Index>::max();
60 explicit SparseTable(std::span<const T> values, Compare compare = Compare())
61 : values_(values), compare_(compare) {
70 std::size_t
size_impl()
const {
return values_.size(); }
78 T
value_at_impl(std::size_t position)
const {
return values_[position]; }
90 std::size_t
arg_min_impl(std::size_t left, std::size_t right)
const {
91 if (left >= right || right > values_.size()) {
94 const std::size_t length = right - left;
95 const std::size_t level = std::bit_width(length) - 1;
96 const std::size_t span = std::size_t{1} << level;
97 const std::size_t first = table_[level][left];
98 const std::size_t second = table_[level][right - span];
99 return better(first, second);
109 std::size_t bytes =
sizeof(*this);
110 bytes += pixie::vector_capacity_bytes(table_);
111 for (
const TableLevel& level : table_) {
112 bytes += pixie::vector_capacity_bytes(level);
128 std::size_t better(std::size_t left, std::size_t right)
const {
129 if (compare_(values_[right], values_[left])) {
132 if (compare_(values_[left], values_[right])) {
135 return std::min(left, right);
149 Index build_better(Index left, Index right)
const {
150 return compare_(values_[right], values_[left]) ? right : left;
163 if (values_.empty()) {
166 if (values_.size() >
static_cast<std::size_t
>(invalid_index)) {
167 throw std::length_error(
"RMQ sparse table index type is too small");
170 table_.reserve(std::bit_width(values_.size()));
171 table_.emplace_back(values_.size());
172 std::iota(table_[0].begin(), table_[0].end(), Index{0});
174 for (std::size_t span = 2, half = 1; span <= values_.size();
175 half = span, span <<= 1) {
176 const std::size_t level = table_.size();
177 table_.emplace_back(values_.size() - span + 1);
178 for (std::size_t i = 0; i < table_[level].size(); ++i) {
179 table_[level][i] =
static_cast<Index
>(
180 build_better(table_[level - 1][i], table_[level - 1][i + half]));
185 template <
class Value, std::
size_t AllocationAlignment>
186 class AlignedAllocator {
188 static_assert(AllocationAlignment >=
alignof(Value));
189 static_assert((AllocationAlignment & (AllocationAlignment - 1)) == 0);
191 using value_type = Value;
193 AlignedAllocator() =
default;
195 template <
class Other>
197 const AlignedAllocator<Other, AllocationAlignment>&)
noexcept {}
199 [[nodiscard]] Value* allocate(std::size_t count) {
203 if (count > std::numeric_limits<std::size_t>::max() /
sizeof(Value)) {
204 throw std::bad_array_new_length();
206 return static_cast<Value*
>(::operator
new(
207 count *
sizeof(Value), std::align_val_t{AllocationAlignment}));
210 void deallocate(Value* pointer, std::size_t)
noexcept {
211 ::operator
delete(pointer, std::align_val_t{AllocationAlignment});
214 template <
class Other>
216 const AlignedAllocator<Other, AllocationAlignment>&)
const noexcept {
220 template <
class Other>
222 const AlignedAllocator<Other, AllocationAlignment>&)
const noexcept {
226 template <
class Other>
228 using other = AlignedAllocator<Other, AllocationAlignment>;
232 template <
class Value, std::
size_t AllocationAlignment>
233 struct LevelAllocator {
234 using type = AlignedAllocator<Value, AllocationAlignment>;
237 template <
class Value>
238 struct LevelAllocator<Value, 0> {
239 using type = std::allocator<Value>;
243 std::vector<Index, typename LevelAllocator<Index, Alignment>::type>;
245 std::span<const T> values_;
247 std::vector<TableLevel> table_;
std::size_t arg_min_impl(std::size_t left, std::size_t right) const
Return the first minimum position in [left, right).
Definition sparse_table.h:90