This documentation is automatically generated by online-judge-tools/verification-helper
#include "sparse_table/sparse_table.hpp"It is a data structure for monoids $(S, \cdot: S \times S \to S, e \in S)$, i.e., an algebraic structure that satisfies the following properties:
Given a static array a of length $N$, it can calculate the product of the elements in a given range [l, r). Unlike a segment tree, it does not support updating elements of the array after construction.
For simplicity, in this document, we assume that the oracles op and e work in constant time.
The following should be defined to instantiate sparse_table.
S.S op(S a, S b).S e().For example, for Range Minimum Query (which is an idempotent operation), the definitions are as follows.
int op(int a, int b) {
return std::min(a, b);
}
int e() {
return std::numeric_limits<int>::max();
}
// std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
// sparse_table<int, op, e> st(v);
sparse_table<S, op, e> st(const std::vector<S>& v)
It creates a sparse table from the elements of vector v.
Constraints
v.size() = $N$Time Complexity
S st.prod(int l, int r)
It returns op(a[l], ..., a[r - 1]). It returns e() if $l = r$.
Constraints
Time Complexity
S st.prod_idempotent(int l, int r)
It returns op(a[l], ..., a[r - 1]). It returns e() if $l = r$.
This is a faster version of prod that can only be used if the operation op is idempotent, meaning it satisfies op(x, x) = x for all x in S.
Common idempotent operations include:
std::min)std::max)&)|)Constraints
op must be idempotent.Time Complexity
#ifndef SPARSE_TABLE_HPP
#define SPARSE_TABLE_HPP
#include <bit>
#include <cassert>
#include <type_traits>
#include <vector>
template <typename S, auto op, auto e> struct sparse_table {
static_assert(std::is_invocable_r_v<S, decltype(op), S, S>,
"op must be a function of type S(S, S)");
static_assert(std::is_invocable_r_v<S, decltype(e)>,
"e must be a function of type S()");
sparse_table(const std::vector<S> &v)
: n_((int)v.size()), width_(std::bit_width(v.size())),
table_(width_, std::vector<S>(v.size())) {
table_[0] = v;
for (auto i = 1; i < width_; ++i) {
for (auto j = 0; j + (1 << i) <= n_; ++j) {
table_[i][j] =
op(table_[i - 1][j], table_[i - 1][j + (1 << (i - 1))]);
}
}
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= n_);
auto sum = e();
for (auto i = width_ - 1; 0 <= i; --i) {
if ((1 << i) <= r - l) {
sum = op(sum, table_[i][l]);
l += (1 << i);
}
}
return sum;
}
S prod_idempotent(int l, int r) {
assert(0 <= l && l <= r && r <= n_);
if (l == r) {
return e();
}
auto i = std::bit_width(unsigned(r - l)) - 1;
return op(table_[i][l], table_[i][r - (1 << i)]);
}
private:
int n_, width_;
std::vector<std::vector<S>> table_;
};
#endif // SPARSE_TABLE_HPP#line 1 "sparse_table/sparse_table.hpp"
#include <bit>
#include <cassert>
#include <type_traits>
#include <vector>
template <typename S, auto op, auto e> struct sparse_table {
static_assert(std::is_invocable_r_v<S, decltype(op), S, S>,
"op must be a function of type S(S, S)");
static_assert(std::is_invocable_r_v<S, decltype(e)>,
"e must be a function of type S()");
sparse_table(const std::vector<S> &v)
: n_((int)v.size()), width_(std::bit_width(v.size())),
table_(width_, std::vector<S>(v.size())) {
table_[0] = v;
for (auto i = 1; i < width_; ++i) {
for (auto j = 0; j + (1 << i) <= n_; ++j) {
table_[i][j] =
op(table_[i - 1][j], table_[i - 1][j + (1 << (i - 1))]);
}
}
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= n_);
auto sum = e();
for (auto i = width_ - 1; 0 <= i; --i) {
if ((1 << i) <= r - l) {
sum = op(sum, table_[i][l]);
l += (1 << i);
}
}
return sum;
}
S prod_idempotent(int l, int r) {
assert(0 <= l && l <= r && r <= n_);
if (l == r) {
return e();
}
auto i = std::bit_width(unsigned(r - l)) - 1;
return op(table_[i][l], table_[i][r - (1 << i)]);
}
private:
int n_, width_;
std::vector<std::vector<S>> table_;
};