This documentation is automatically generated by online-judge-tools/verification-helper
#include "DataStructure/segtree_dual.hpp"
双対セグメント木は区間更新、1点収得を $\text{O}(\log N)$ で求めることができるデータ構造である.
遅延評価セグメント木と比較すると区間収得のための更新を行わないため、定数倍が良い。
実装は AtCoder Library の遅延セグ木から遅延評価のための配列 lazy
だけを残したようなものになっている。
宣言を簡易的にするために、mapping
と composition
、モノイドの型 S
と写像の型 F
を同じものとなるように設計しているため、異なるものが欲しい場合は遅延セグ木を使う。
以下の3つを宣言する必要がある。
S
: 写像の型S mapping(S after, S before)
: before
に after
を作用させる関数。(合成写像と兼用)S id()
: 恒等写像。 mapping(id(), f) = mapping(f, id()) = f
が満たされるようにする
テンプレート引数の例 (区間加算・1点収得)。適宜書き換えて使用する。
// dual_segtree<S, mapping, id> seg(size); のように宣言
using S = int;
// bf に af を作用させた時の変化
S mapping(S af, S bf){ return bf + af; }
// 恒等写像
S id(){ return 0; }
関数名など | 機能 | 計算量 |
---|---|---|
(1) dual_segtree<S, mapping, id>(int N) (2) dual_segtree<S, mapping, id>(std::vector<S> vec)
|
(1) $N$ 個の要素を持つ配列を作る。初期値は id() (2) 双対セグ木の要素を vec で初期化する。 |
$\text{O}(N)$ |
S a[p] |
a[p] を収得する。 |
$\text{O}(\log N)$ |
(1)void apply(int p, S f) (2) void apply(int l, int r, S f)
|
(1) a[p] = mapping(f, a[p]) を行う。(2) $l \leq i < r$ について a[i] = mapping(f, a[i]) を行う。 |
$\text{O}(\log N)$ |
template <class S, S (*mapping)(S, S), S (*id)()> struct dual_segtree {
public:
dual_segtree() : dual_segtree(0) {}
dual_segtree(int n) : dual_segtree(std::vector<S>(n, id())) {}
dual_segtree(const std::vector<S>& v) : _n(int(v.size())) {
log = ceil_pow2(_n);
size = 1 << log;
d = std::vector<S>(2 * size, id());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
}
const S& operator[](int p) const {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
return d[p];
}
S& operator[](int p) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
return d[p];
}
void apply(int p, S f) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
d[p] = mapping(f, d[p]);
}
void apply(int l, int r, S f) {
assert(0 <= l && l <= r && r <= _n);
if (l == r) return;
l += size;
r += size;
for (int i = log; i >= 1; i--) {
if (((l >> i) << i) != l) push(l >> i);
if (((r >> i) << i) != r) push((r - 1) >> i);
}
while (l < r) {
if (l & 1) all_apply(l++, f);
if (r & 1) all_apply(--r, f);
l >>= 1;
r >>= 1;
}
}
private:
int _n, size, log;
std::vector<S> d;
void all_apply(int k, S f) {
d[k] = mapping(f, d[k]);
}
void push(int k) {
all_apply(2 * k, d[k]);
all_apply(2 * k + 1, d[k]);
d[k] = id();
}
int ceil_pow2(int n) {
int x = 0;
while ((1U << x) < (unsigned int)(n)) x++;
return x;
}
};
#line 1 "DataStructure/segtree_dual.hpp"
template <class S, S (*mapping)(S, S), S (*id)()> struct dual_segtree {
public:
dual_segtree() : dual_segtree(0) {}
dual_segtree(int n) : dual_segtree(std::vector<S>(n, id())) {}
dual_segtree(const std::vector<S>& v) : _n(int(v.size())) {
log = ceil_pow2(_n);
size = 1 << log;
d = std::vector<S>(2 * size, id());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
}
const S& operator[](int p) const {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
return d[p];
}
S& operator[](int p) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
return d[p];
}
void apply(int p, S f) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
d[p] = mapping(f, d[p]);
}
void apply(int l, int r, S f) {
assert(0 <= l && l <= r && r <= _n);
if (l == r) return;
l += size;
r += size;
for (int i = log; i >= 1; i--) {
if (((l >> i) << i) != l) push(l >> i);
if (((r >> i) << i) != r) push((r - 1) >> i);
}
while (l < r) {
if (l & 1) all_apply(l++, f);
if (r & 1) all_apply(--r, f);
l >>= 1;
r >>= 1;
}
}
private:
int _n, size, log;
std::vector<S> d;
void all_apply(int k, S f) {
d[k] = mapping(f, d[k]);
}
void push(int k) {
all_apply(2 * k, d[k]);
all_apply(2 * k + 1, d[k]);
d[k] = id();
}
int ceil_pow2(int n) {
int x = 0;
while ((1U << x) < (unsigned int)(n)) x++;
return x;
}
};