C++ Library for Competitive Programming
#include "emthrm/data_structure/dual_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_DUAL_SEGMENT_TREE_HPP_
#define EMTHRM_DATA_STRUCTURE_DUAL_SEGMENT_TREE_HPP_
#include <bit>
#include <concepts>
#include <cstdint>
#include <optional>
#include <utility>
#include <vector>
namespace emthrm {
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 {
using Elem = typename T::Elem;
using OperatorMonoid = typename T::OperatorMonoid;
explicit DualSegmentTree(const std::vector<Elem>& data)
: n(data.size()), height(std::countr_zero(std::bit_ceil(data.size()))),
p2(1 << height), data(data), lazy(p2, T::id()) {}
void set(const int idx, const Elem val) {
propagate_line(idx);
data[idx] = val;
}
void apply(const int idx, const OperatorMonoid val) {
propagate_line(idx);
data[idx] = T::apply(data[idx], val);
}
void apply(int left, int right, const OperatorMonoid val) {
if (right <= left) [[unlikely]] return;
propagate_line(left, std::countr_zero(static_cast<unsigned int>(left)));
propagate_line(right, std::countr_zero(static_cast<unsigned int>(right)));
left += p2;
right += p2;
if (left & 1) {
data[left - p2] = T::apply(data[left - p2], val);
++left;
}
if (right & 1) {
--right;
data[right - p2] = T::apply(data[right - p2], val);
}
for (left >>= 1, right >>= 1; left < right; left >>= 1, right >>= 1) {
if (left & 1) {
lazy[left] = T::merge(lazy[left], val);
++left;
}
if (right & 1) {
--right;
lazy[right] = T::merge(lazy[right], val);
}
}
}
Elem operator[](const int idx) {
propagate_line(idx);
return data[idx];
}
private:
const int n, height, p2;
std::vector<Elem> data;
std::vector<OperatorMonoid> lazy;
void propagate(const int idx) {
if (lazy[idx] == T::id()) return;
const int child = idx << 1;
if (child >= p2) {
if (child - p2 < n) {
data[child - p2] = T::apply(data[child - p2], lazy[idx]);
if (child - p2 + 1 < n) {
data[child - p2 + 1] = T::apply(data[child - p2 + 1], lazy[idx]);
}
}
} else {
lazy[child] = T::merge(lazy[child], lazy[idx]);
lazy[child + 1] = T::merge(lazy[child + 1], lazy[idx]);
}
lazy[idx] = T::id();
}
void propagate_line(const int idx, const int until = 0) {
const int node = idx + p2;
for (int i = height; i > until; --i) {
propagate(node >> i);
}
}
};
namespace monoid {
template <typename T>
struct RangeUpdateQuery {
using Elem = T;
using OperatorMonoid = std::optional<Elem>;
static constexpr OperatorMonoid id() { return std::nullopt; }
static OperatorMonoid merge(const OperatorMonoid& a,
const OperatorMonoid& b) {
return b.has_value() ? b : a;
}
static Elem apply(const Elem& a, const OperatorMonoid& b) {
return b.has_value() ? b.value() : a;
}
};
template <typename T>
struct RangeAddQuery {
using Elem = T;
using OperatorMonoid = T;
static constexpr OperatorMonoid id() { return 0; }
static OperatorMonoid merge(const OperatorMonoid& a,
const OperatorMonoid& b) {
return a + b;
}
static Elem apply(const Elem& a, const OperatorMonoid& b) { return a + b; }
};
} // namespace monoid
} // namespace emthrm
#endif // EMTHRM_DATA_STRUCTURE_DUAL_SEGMENT_TREE_HPP_
#line 1 "include/emthrm/data_structure/dual_segment_tree.hpp"
#include <bit>
#include <concepts>
#include <cstdint>
#include <optional>
#include <utility>
#include <vector>
namespace emthrm {
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 {
using Elem = typename T::Elem;
using OperatorMonoid = typename T::OperatorMonoid;
explicit DualSegmentTree(const std::vector<Elem>& data)
: n(data.size()), height(std::countr_zero(std::bit_ceil(data.size()))),
p2(1 << height), data(data), lazy(p2, T::id()) {}
void set(const int idx, const Elem val) {
propagate_line(idx);
data[idx] = val;
}
void apply(const int idx, const OperatorMonoid val) {
propagate_line(idx);
data[idx] = T::apply(data[idx], val);
}
void apply(int left, int right, const OperatorMonoid val) {
if (right <= left) [[unlikely]] return;
propagate_line(left, std::countr_zero(static_cast<unsigned int>(left)));
propagate_line(right, std::countr_zero(static_cast<unsigned int>(right)));
left += p2;
right += p2;
if (left & 1) {
data[left - p2] = T::apply(data[left - p2], val);
++left;
}
if (right & 1) {
--right;
data[right - p2] = T::apply(data[right - p2], val);
}
for (left >>= 1, right >>= 1; left < right; left >>= 1, right >>= 1) {
if (left & 1) {
lazy[left] = T::merge(lazy[left], val);
++left;
}
if (right & 1) {
--right;
lazy[right] = T::merge(lazy[right], val);
}
}
}
Elem operator[](const int idx) {
propagate_line(idx);
return data[idx];
}
private:
const int n, height, p2;
std::vector<Elem> data;
std::vector<OperatorMonoid> lazy;
void propagate(const int idx) {
if (lazy[idx] == T::id()) return;
const int child = idx << 1;
if (child >= p2) {
if (child - p2 < n) {
data[child - p2] = T::apply(data[child - p2], lazy[idx]);
if (child - p2 + 1 < n) {
data[child - p2 + 1] = T::apply(data[child - p2 + 1], lazy[idx]);
}
}
} else {
lazy[child] = T::merge(lazy[child], lazy[idx]);
lazy[child + 1] = T::merge(lazy[child + 1], lazy[idx]);
}
lazy[idx] = T::id();
}
void propagate_line(const int idx, const int until = 0) {
const int node = idx + p2;
for (int i = height; i > until; --i) {
propagate(node >> i);
}
}
};
namespace monoid {
template <typename T>
struct RangeUpdateQuery {
using Elem = T;
using OperatorMonoid = std::optional<Elem>;
static constexpr OperatorMonoid id() { return std::nullopt; }
static OperatorMonoid merge(const OperatorMonoid& a,
const OperatorMonoid& b) {
return b.has_value() ? b : a;
}
static Elem apply(const Elem& a, const OperatorMonoid& b) {
return b.has_value() ? b.value() : a;
}
};
template <typename T>
struct RangeAddQuery {
using Elem = T;
using OperatorMonoid = T;
static constexpr OperatorMonoid id() { return 0; }
static OperatorMonoid merge(const OperatorMonoid& a,
const OperatorMonoid& b) {
return a + b;
}
static Elem apply(const Elem& a, const OperatorMonoid& b) { return a + b; }
};
} // namespace monoid
} // namespace emthrm