This documentation is automatically generated by online-judge-tools/verification-helper
#include "ds/segtree/dynamic_dual_segtree.hpp"// Source: https://github.com/maspypy/library/blob/main/ds/segtree/dynamic_dual_segtree.hpp
#include "ds/node_pool.hpp"
// Q*2logN 程度必要
// https://qoj.ac/contest/1516/problem/8240
template <typename Monoid, bool PERSISTENT>
struct Dynamic_Dual_SegTree {
using MX = Monoid;
using X = typename MX::value_type;
struct Node {
Node *l, *r;
X x;
};
const ll L0, R0;
Node_Pool<Node> pool;
using np = Node *;
Dynamic_Dual_SegTree(ll L0, ll R0) : L0(L0), R0(R0) {}
np new_root() { return new_node(MX::id()); }
np new_node(const X x = MX::id()) {
np c = pool.create();
c->l = c->r = nullptr, c->x = x;
return c;
}
np new_node(const vc<X> &dat) {
assert(L0 == 0 && R0 == len(dat));
auto dfs = [&](auto &dfs, ll l, ll r) -> Node * {
if (l == r) return nullptr;
if (r == l + 1) return new_node(dat[l]);
ll m = (l + r) / 2;
np l_root = dfs(dfs, l, m), r_root = dfs(dfs, m, r);
X x = MX::op(l_root->x, r_root->x);
np root = new_node();
root->l = l_root, root->r = r_root;
return root;
};
return dfs(dfs, 0, len(dat));
}
X get(np root, ll i) {
if (!root) return MX::id();
X x = MX::id();
get_rec(root, L0, R0, i, x);
return x;
}
np apply(np root, ll l, ll r, const X &x) {
if (l == r) return root;
assert(root && L0 <= l && l < r && r <= R0);
root = clone(root);
apply_rec(root, L0, R0, l, r, x);
return root;
}
// root[l:r) を other[l:r)*x で上書きしたものを返す
np copy_interval(np root, np other, ll l, ll r, X x) {
if (root == other) return root;
root = clone(root);
copy_interval_rec(root, other, L0, R0, l, r, x);
return root;
}
void reset() { pool.reset(); }
vc<X> get_all(np root) {
vc<X> res;
auto dfs = [&](auto &dfs, np c, ll L, ll R, X x) -> void {
if (!c) {
FOR(R - L) res.eb(x);
return;
}
x = MX::op(c->x, x);
if (R == L + 1) {
res.eb(x);
return;
}
ll M = (L + R) / 2;
dfs(dfs, c->l, L, M, x);
dfs(dfs, c->r, M, R, x);
};
dfs(dfs, root, L0, R0, MX::id());
return res;
}
private:
np clone(np c) {
if (!c || !PERSISTENT) return c;
return pool.clone(c);
}
void apply_rec(np c, ll l, ll r, ll ql, ll qr, const X &a) {
// もう c は新しくしてある
assert(c);
chmax(ql, l), chmin(qr, r);
if (ql >= qr) return;
if (l == ql && r == qr) {
c->x = MX::op(c->x, a);
return;
}
// push
c->l = (c->l ? clone(c->l) : new_node());
c->r = (c->r ? clone(c->r) : new_node());
c->l->x = MX::op(c->l->x, c->x);
c->r->x = MX::op(c->r->x, c->x);
c->x = MX::id();
ll m = (l + r) / 2;
apply_rec(c->l, l, m, ql, qr, a), apply_rec(c->r, m, r, ql, qr, a);
return;
}
void copy_interval_rec(np c, np d, ll l, ll r, ll ql, ll qr, X x) {
// c[ql,qr) <- d[ql,qr) * x
// もう c は新しくしてある
assert(c);
chmax(ql, l), chmin(qr, r);
if (ql >= qr) return;
if (l == ql && r == qr) {
if (d)
c->x = MX::op(d->x, x), c->l = d->l, c->r = d->r;
else
c->x = x, c->l = nullptr, c->r = nullptr;
return;
}
// push
c->l = (c->l ? clone(c->l) : new_node());
c->r = (c->r ? clone(c->r) : new_node());
c->l->x = MX::op(c->l->x, c->x);
c->r->x = MX::op(c->r->x, c->x);
c->x = MX::id();
ll m = (l + r) / 2;
if (d) x = MX::op(d->x, x);
copy_interval_rec(c->l, (d && d->l ? d->l : nullptr), l, m, ql, qr, x);
copy_interval_rec(c->r, (d && d->r ? d->r : nullptr), m, r, ql, qr, x);
return;
}
void get_rec(np c, ll l, ll r, ll i, X &x) {
if (!c) return;
x = MX::op(c->x, x);
if (r == l + 1) {
return;
}
ll m = (l + r) / 2;
if (i < m) return get_rec(c->l, l, m, i, x);
return get_rec(c->r, m, r, i, x);
}
};#line 1 "ds/segtree/dynamic_dual_segtree.hpp"
// Source: https://github.com/maspypy/library/blob/main/ds/segtree/dynamic_dual_segtree.hpp
#line 1 "ds/node_pool.hpp"
// Source: https://github.com/maspypy/library/blob/main/ds/node_pool.hpp
// マルチテストケースでも確保済み chunk を再利用する
template <class Node>
struct Node_Pool {
union Slot {
Node node;
Slot* next;
Slot() {}
~Slot() {}
};
using np = Node*;
static constexpr int CHUNK_SIZE = 1 << 12;
vc<unique_ptr<Slot[]>> chunks;
int chunk_id = 0;
int pos = 0;
Slot* free_head = nullptr;
~Node_Pool() {
auto& cache = chunk_cache();
for (auto& p : chunks) cache.eb(std::move(p));
}
template <class... Args>
np create(Args&&... args) {
Slot* s = new_slot();
return ::new (&s->node) Node(forward<Args>(args)...);
}
np clone(const np x) {
assert(x);
Slot* s = new_slot();
return ::new (&s->node) Node(*x);
}
void destroy(np x) {
if (!x) return;
x->~Node();
Slot* s = reinterpret_cast<Slot*>(x);
s->next = free_head;
free_head = s;
}
// 全 node を無効化する。
// 確保済み chunk は解放せず、次回以降に再利用する。
void reset() {
free_head = nullptr;
chunk_id = 0;
pos = 0;
}
int used() const { return chunk_id * CHUNK_SIZE + pos; }
private:
static vc<unique_ptr<Slot[]>>& chunk_cache() {
// static Node_Pool の destructor より先に破棄されないようにする。
static auto* cache = new vc<unique_ptr<Slot[]>>();
return *cache;
}
void alloc_chunk() {
auto& cache = chunk_cache();
if (cache.empty()) {
chunks.eb(make_unique<Slot[]>(CHUNK_SIZE));
} else {
chunks.eb(std::move(cache.back()));
cache.pop_back();
}
}
Slot* new_slot() {
if (free_head) {
Slot* s = free_head;
free_head = free_head->next;
return s;
}
if (chunk_id == len(chunks)) alloc_chunk();
Slot* s = &chunks[chunk_id][pos++];
if (pos == CHUNK_SIZE) {
++chunk_id;
pos = 0;
}
return s;
}
};
#line 3 "ds/segtree/dynamic_dual_segtree.hpp"
// Q*2logN 程度必要
// https://qoj.ac/contest/1516/problem/8240
template <typename Monoid, bool PERSISTENT>
struct Dynamic_Dual_SegTree {
using MX = Monoid;
using X = typename MX::value_type;
struct Node {
Node *l, *r;
X x;
};
const ll L0, R0;
Node_Pool<Node> pool;
using np = Node *;
Dynamic_Dual_SegTree(ll L0, ll R0) : L0(L0), R0(R0) {}
np new_root() { return new_node(MX::id()); }
np new_node(const X x = MX::id()) {
np c = pool.create();
c->l = c->r = nullptr, c->x = x;
return c;
}
np new_node(const vc<X> &dat) {
assert(L0 == 0 && R0 == len(dat));
auto dfs = [&](auto &dfs, ll l, ll r) -> Node * {
if (l == r) return nullptr;
if (r == l + 1) return new_node(dat[l]);
ll m = (l + r) / 2;
np l_root = dfs(dfs, l, m), r_root = dfs(dfs, m, r);
X x = MX::op(l_root->x, r_root->x);
np root = new_node();
root->l = l_root, root->r = r_root;
return root;
};
return dfs(dfs, 0, len(dat));
}
X get(np root, ll i) {
if (!root) return MX::id();
X x = MX::id();
get_rec(root, L0, R0, i, x);
return x;
}
np apply(np root, ll l, ll r, const X &x) {
if (l == r) return root;
assert(root && L0 <= l && l < r && r <= R0);
root = clone(root);
apply_rec(root, L0, R0, l, r, x);
return root;
}
// root[l:r) を other[l:r)*x で上書きしたものを返す
np copy_interval(np root, np other, ll l, ll r, X x) {
if (root == other) return root;
root = clone(root);
copy_interval_rec(root, other, L0, R0, l, r, x);
return root;
}
void reset() { pool.reset(); }
vc<X> get_all(np root) {
vc<X> res;
auto dfs = [&](auto &dfs, np c, ll L, ll R, X x) -> void {
if (!c) {
FOR(R - L) res.eb(x);
return;
}
x = MX::op(c->x, x);
if (R == L + 1) {
res.eb(x);
return;
}
ll M = (L + R) / 2;
dfs(dfs, c->l, L, M, x);
dfs(dfs, c->r, M, R, x);
};
dfs(dfs, root, L0, R0, MX::id());
return res;
}
private:
np clone(np c) {
if (!c || !PERSISTENT) return c;
return pool.clone(c);
}
void apply_rec(np c, ll l, ll r, ll ql, ll qr, const X &a) {
// もう c は新しくしてある
assert(c);
chmax(ql, l), chmin(qr, r);
if (ql >= qr) return;
if (l == ql && r == qr) {
c->x = MX::op(c->x, a);
return;
}
// push
c->l = (c->l ? clone(c->l) : new_node());
c->r = (c->r ? clone(c->r) : new_node());
c->l->x = MX::op(c->l->x, c->x);
c->r->x = MX::op(c->r->x, c->x);
c->x = MX::id();
ll m = (l + r) / 2;
apply_rec(c->l, l, m, ql, qr, a), apply_rec(c->r, m, r, ql, qr, a);
return;
}
void copy_interval_rec(np c, np d, ll l, ll r, ll ql, ll qr, X x) {
// c[ql,qr) <- d[ql,qr) * x
// もう c は新しくしてある
assert(c);
chmax(ql, l), chmin(qr, r);
if (ql >= qr) return;
if (l == ql && r == qr) {
if (d)
c->x = MX::op(d->x, x), c->l = d->l, c->r = d->r;
else
c->x = x, c->l = nullptr, c->r = nullptr;
return;
}
// push
c->l = (c->l ? clone(c->l) : new_node());
c->r = (c->r ? clone(c->r) : new_node());
c->l->x = MX::op(c->l->x, c->x);
c->r->x = MX::op(c->r->x, c->x);
c->x = MX::id();
ll m = (l + r) / 2;
if (d) x = MX::op(d->x, x);
copy_interval_rec(c->l, (d && d->l ? d->l : nullptr), l, m, ql, qr, x);
copy_interval_rec(c->r, (d && d->r ? d->r : nullptr), m, r, ql, qr, x);
return;
}
void get_rec(np c, ll l, ll r, ll i, X &x) {
if (!c) return;
x = MX::op(c->x, x);
if (r == l + 1) {
return;
}
ll m = (l + r) / 2;
if (i < m) return get_rec(c->l, l, m, i, x);
return get_rec(c->r, m, r, i, x);
}
};