C++ Library for Competitive Programming
#include "emthrm/data_structure/segment_tree.hpp"
モノイドであるデータに対して高速に区間クエリを処理する(完全)二分木である。
$\langle O(N), O(\log{N}) \rangle$
template <typename T>
requires requires {
typename T::Monoid;
{T::id()} -> std::same_as<typename T::Monoid>;
{T::merge(std::declval<typename T::Monoid>(),
std::declval<typename T::Monoid>())}
-> std::same_as<typename T::Monoid>;
}
struct SegmentTree;
T
:モノイドを表す構造体であり、以下の型エイリアスと静的メンバ関数を必要とする。
Monoid
:要素型static constexpr Monoid id();
:単位元static Monoid merge(const Monoid&, const Monoid&);
:二項演算 $\circ$名前 | 効果・戻り値 |
---|---|
explicit SegmentTree(const int n); |
要素数 $N$ のオブジェクトを構築する。 |
explicit SegmentTree(const std::vector<Monoid>& a); |
$A$ に対してオブジェクトを構築する。 |
void set(int idx, const Monoid val); |
$A_{\mathrm{idx}} \gets \mathrm{val}$ |
Monoid get(int left, int right) const; |
$A_{\mathrm{left}} \circ \cdots \circ A_{\mathrm{right}}$ |
Monoid operator[](const int idx) const; |
$A_{\mathrm{idx}}$ |
template <typename G> int find_right(int left, const G g);
|
g(get(left, right + 1)) = false を満たす最小の $\mathrm{right}$。ただし存在しないときは $N$ を返す。 |
template <typename G> int find_left(int right, const G g);
|
g(get(left, right)) = false を満たす最大の $\mathrm{left}$。ただし存在しないときは $-1$ を返す。 |
名前 | 説明 |
---|---|
Monoid |
T::Monoid |
template <typename T>
requires requires {
typename T::Monoid;
typename T::OperatorMonoid;
{T::m_id()} -> std::same_as<typename T::Monoid>;
{T::o_id()} -> std::same_as<typename T::OperatorMonoid>;
{T::m_merge(std::declval<typename T::Monoid>(),
std::declval<typename T::Monoid>())}
-> std::same_as<typename T::Monoid>;
{T::o_merge(std::declval<typename T::OperatorMonoid>(),
std::declval<typename T::OperatorMonoid>())}
-> std::same_as<typename T::OperatorMonoid>;
{T::apply(std::declval<typename T::Monoid>(),
std::declval<typename T::OperatorMonoid>())}
-> std::same_as<typename T::Monoid>;
}
struct LazySegmentTree;
T
:モノイドを表す構造体であり、以下の型エイリアスと静的メンバ関数を必要とする。
Monoid
:要素型OperatorMonoid
:作用素モノイドの要素型static constexpr Monoid m_id();
:単位元static constexpr OperatorMonoid o_id();
:作用素モノイドの単位元static Monoid m_merge(const Monoid&, const Monoid&);
:二項演算 $\circ$static OperatorMonoid o_merge(const OperatorMonoid&, const OperatorMonoid&);
static Monoid apply(const Monoid&, const OperatorMonoid&);
名前 | 効果・戻り値 |
---|---|
explicit LazySegmentTree(const int n); |
要素数 $N$ のオブジェクトを構築する。 |
explicit LazySegmentTree(const std::vector<Monoid>& a); |
$A$ に対してオブジェクトを構築する。 |
void set(int idx, const Monoid val); |
$A_{\mathrm{idx}} \gets \mathrm{val}$ |
void apply(int idx, const OperatorMonoid val); |
$\mathrm{idx}$ における変更クエリ |
void apply(int left, int right, const OperatorMonoid val); |
$[\mathrm{left}, \mathrm{right})$ における変更クエリ |
Monoid get(int left, int right); |
$[\mathrm{left}, \mathrm{right})$ における解答クエリ |
Monoid operator[](const int idx); |
$A_{\mathrm{idx}}$ |
template <typename G> int find_right(int left, const G g);
|
g(get(left, right + 1)) = false を満たす最小の $\mathrm{right}$。ただし存在しない場合は $N$ を返す。 |
template <typename G> int find_left(int right, const G g);
|
g(get(left, right)) = false を満たす最大の $\mathrm{left}$。ただし存在しない場合は $-1$ を返す。 |
名前 | 説明 |
---|---|
Monoid |
T::Monoid |
OperatorMonoid |
T::OperatorMonoid |
template <typename T>
requires requires {
typename T::Elem;
typename T::OperatorMonoid;
{T::id()} -> std::same_as<typename T::OperatorMonoid>;
{T::merge(std::declval<typename T::OperatorMonoid>(),
std::declval<typename T::OperatorMonoid>())}
-> std::same_as<typename T::OperatorMonoid>;
{T::apply(std::declval<typename T::Elem>(),
std::declval<typename T::OperatorMonoid>())}
-> std::same_as<typename T::Elem>;
}
struct DualSegmentTree;
T
:以下の型エイリアスと静的メンバ関数を必要とする。
Eval
:要素型OperatorMonoid
:作用素モノイドの要素型static constexpr OperatorMonoid id();
:作用素モノイドの単位元static OperatorMonoid merge(const OperatorMonoid&, const OperatorMonoid&);
static Elem apply(const Elem&, const OperatorMonoid&);
名前 | 効果・戻り値 |
---|---|
explicit DualSegmentTree(const std::vector<Elem>& a); |
$A$ に対してオブジェクトを構築する。 |
void set(const int idx, const Elem val); |
$A_{\mathrm{idx}} \gets \mathrm{val}$ |
void apply(const int idx, const OperatorMonoid val); |
$\mathrm{idx}$ における変更クエリ |
void apply(int left, int right, const OperatorMonoid val); |
$[\mathrm{left}, \mathrm{right})$ における変更クエリ |
Elem operator[](const int idx); |
$A_{\mathrm{idx}}$ |
名前 | 説明 |
---|---|
Elem |
T::Elem |
OperatorMonoid |
T::OperatorMonoid |
セグメント木
遅延伝播セグメント木
双対セグメント木
get
#ifndef EMTHRM_DATA_STRUCTURE_SEGMENT_TREE_HPP_
#define EMTHRM_DATA_STRUCTURE_SEGMENT_TREE_HPP_
#include <algorithm>
#include <bit>
#include <limits>
#include <type_traits>
#include <vector>
namespace emthrm {
template <typename T>
requires requires {
typename T::Monoid;
{T::id()} -> std::same_as<typename T::Monoid>;
{T::merge(std::declval<typename T::Monoid>(),
std::declval<typename T::Monoid>())}
-> std::same_as<typename T::Monoid>;
}
struct SegmentTree {
using Monoid = typename T::Monoid;
explicit SegmentTree(const int n)
: SegmentTree(std::vector<Monoid>(n, T::id())) {}
explicit SegmentTree(const std::vector<Monoid>& a)
: n(a.size()), p2(std::bit_ceil(a.size())) {
dat.assign(p2 << 1, T::id());
std::copy(a.begin(), a.end(), dat.begin() + p2);
for (int i = p2 - 1; i > 0; --i) {
dat[i] = T::merge(dat[i << 1], dat[(i << 1) + 1]);
}
}
void set(int idx, const Monoid val) {
idx += p2;
dat[idx] = val;
while (idx >>= 1) dat[idx] = T::merge(dat[idx << 1], dat[(idx << 1) + 1]);
}
Monoid get(int left, int right) const {
Monoid res_l = T::id(), res_r = T::id();
for (left += p2, right += p2; left < right; left >>= 1, right >>= 1) {
if (left & 1) res_l = T::merge(res_l, dat[left++]);
if (right & 1) res_r = T::merge(dat[--right], res_r);
}
return T::merge(res_l, res_r);
}
Monoid operator[](const int idx) const { return dat[idx + p2]; }
template <typename G>
int find_right(int left, const G g) const {
if (left >= n) [[unlikely]] return n;
Monoid val = T::id();
left += p2;
do {
while (!(left & 1)) left >>= 1;
Monoid nxt = T::merge(val, dat[left]);
if (!g(nxt)) {
while (left < p2) {
left <<= 1;
nxt = T::merge(val, dat[left]);
if (g(nxt)) {
val = nxt;
++left;
}
}
return left - p2;
}
val = nxt;
++left;
} while (!std::has_single_bit(static_cast<unsigned int>(left)));
return n;
}
template <typename G>
int find_left(int right, const G g) const {
if (right <= 0) [[unlikely]] return -1;
Monoid val = T::id();
right += p2;
do {
--right;
while (right > 1 && (right & 1)) right >>= 1;
Monoid nxt = T::merge(dat[right], val);
if (!g(nxt)) {
while (right < p2) {
right = (right << 1) + 1;
nxt = T::merge(dat[right], val);
if (g(nxt)) {
val = nxt;
--right;
}
}
return right - p2;
}
val = nxt;
} while (!std::has_single_bit(static_cast<unsigned int>(right)));
return -1;
}
private:
const int n, p2;
std::vector<Monoid> dat;
};
namespace monoid {
template <typename T>
struct RangeMinimumQuery {
using Monoid = T;
static constexpr Monoid id() { return std::numeric_limits<Monoid>::max(); }
static Monoid merge(const Monoid& a, const Monoid& b) {
return std::min(a, b);
}
};
template <typename T>
struct RangeMaximumQuery {
using Monoid = T;
static constexpr Monoid id() { return std::numeric_limits<Monoid>::lowest(); }
static Monoid merge(const Monoid& a, const Monoid& b) {
return std::max(a, b);
}
};
template <typename T>
struct RangeSumQuery {
using Monoid = T;
static constexpr Monoid id() { return 0; }
static Monoid merge(const Monoid& a, const Monoid& b) { return a + b; }
};
} // namespace monoid
} // namespace emthrm
#endif // EMTHRM_DATA_STRUCTURE_SEGMENT_TREE_HPP_
#line 1 "include/emthrm/data_structure/segment_tree.hpp"
#include <algorithm>
#include <bit>
#include <limits>
#include <type_traits>
#include <vector>
namespace emthrm {
template <typename T>
requires requires {
typename T::Monoid;
{T::id()} -> std::same_as<typename T::Monoid>;
{T::merge(std::declval<typename T::Monoid>(),
std::declval<typename T::Monoid>())}
-> std::same_as<typename T::Monoid>;
}
struct SegmentTree {
using Monoid = typename T::Monoid;
explicit SegmentTree(const int n)
: SegmentTree(std::vector<Monoid>(n, T::id())) {}
explicit SegmentTree(const std::vector<Monoid>& a)
: n(a.size()), p2(std::bit_ceil(a.size())) {
dat.assign(p2 << 1, T::id());
std::copy(a.begin(), a.end(), dat.begin() + p2);
for (int i = p2 - 1; i > 0; --i) {
dat[i] = T::merge(dat[i << 1], dat[(i << 1) + 1]);
}
}
void set(int idx, const Monoid val) {
idx += p2;
dat[idx] = val;
while (idx >>= 1) dat[idx] = T::merge(dat[idx << 1], dat[(idx << 1) + 1]);
}
Monoid get(int left, int right) const {
Monoid res_l = T::id(), res_r = T::id();
for (left += p2, right += p2; left < right; left >>= 1, right >>= 1) {
if (left & 1) res_l = T::merge(res_l, dat[left++]);
if (right & 1) res_r = T::merge(dat[--right], res_r);
}
return T::merge(res_l, res_r);
}
Monoid operator[](const int idx) const { return dat[idx + p2]; }
template <typename G>
int find_right(int left, const G g) const {
if (left >= n) [[unlikely]] return n;
Monoid val = T::id();
left += p2;
do {
while (!(left & 1)) left >>= 1;
Monoid nxt = T::merge(val, dat[left]);
if (!g(nxt)) {
while (left < p2) {
left <<= 1;
nxt = T::merge(val, dat[left]);
if (g(nxt)) {
val = nxt;
++left;
}
}
return left - p2;
}
val = nxt;
++left;
} while (!std::has_single_bit(static_cast<unsigned int>(left)));
return n;
}
template <typename G>
int find_left(int right, const G g) const {
if (right <= 0) [[unlikely]] return -1;
Monoid val = T::id();
right += p2;
do {
--right;
while (right > 1 && (right & 1)) right >>= 1;
Monoid nxt = T::merge(dat[right], val);
if (!g(nxt)) {
while (right < p2) {
right = (right << 1) + 1;
nxt = T::merge(dat[right], val);
if (g(nxt)) {
val = nxt;
--right;
}
}
return right - p2;
}
val = nxt;
} while (!std::has_single_bit(static_cast<unsigned int>(right)));
return -1;
}
private:
const int n, p2;
std::vector<Monoid> dat;
};
namespace monoid {
template <typename T>
struct RangeMinimumQuery {
using Monoid = T;
static constexpr Monoid id() { return std::numeric_limits<Monoid>::max(); }
static Monoid merge(const Monoid& a, const Monoid& b) {
return std::min(a, b);
}
};
template <typename T>
struct RangeMaximumQuery {
using Monoid = T;
static constexpr Monoid id() { return std::numeric_limits<Monoid>::lowest(); }
static Monoid merge(const Monoid& a, const Monoid& b) {
return std::max(a, b);
}
};
template <typename T>
struct RangeSumQuery {
using Monoid = T;
static constexpr Monoid id() { return 0; }
static Monoid merge(const Monoid& a, const Monoid& b) { return a + b; }
};
} // namespace monoid
} // namespace emthrm