range_set_range_product.hpp¶
支持区间赋成同一个值,并查询区间上的非交换乘积;适合矩阵或函数复合等有顺序的聚合。
Complexity: Time: O(n) construction and O(log n) per range assignment or ordered range product. Space: O(n).
AC 记录:range_set_range_composite。
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(n) construction and O(log n) per range assignment or
/// ordered range product.
/// Space: O(n).
#include <algorithm>
#include <cassert>
#include <vector>
namespace noya {
/// @brief Segment tree for assigning one value to a range and taking an
/// ordered monoid product. For every assigned value, powers for all segment
/// lengths are cached in a circular table. Lazy nodes refer to those cached
/// powers, so a full-cover assignment is constant time and no idempotence or
/// commutativity is required from the monoid.
template <class S, auto op, auto e> struct range_set_range_product {
int n = 0;
int sz = 1;
int log = 0;
int ptr = 0;
std::vector<int> lz;
std::vector<int> len;
std::vector<S> pw;
std::vector<S> prd;
range_set_range_product() = default;
explicit range_set_range_product(const std::vector<S> &a) {
build(a);
}
void build(const std::vector<S> &a) {
n = int(a.size());
sz = 1;
log = 0;
while (sz < std::max(1, n)) {
sz <<= 1;
log++;
}
ptr = 0;
lz.assign(sz, -1);
len.assign(sz * 2, sz);
for (int u = sz - 1; u >= 1; u--) {
len[u] = len[u << 1] >> 1;
}
pw.assign(sz * 2, e());
prd.assign(sz * 2, e());
for (int i = 0; i < n; i++) {
prd[sz + i] = a[i];
}
for (int u = sz - 1; u >= 1; u--) {
prd[u] = op(prd[u << 1], prd[u << 1 | 1]);
}
}
void assign(int l, int r, S val) {
assert(0 <= l && l <= r && r <= n);
if (l == r) {
return;
}
int tag = ptr++;
if (ptr == sz * 2) {
ptr = 0;
}
pw[index(tag - sz)] = val;
for (int h = 1; h <= log; h++) {
val = op(val, val);
pw[index(tag - (sz >> h))] = val;
}
assign_rec(l, r, tag, 1, 0, sz);
propagate_path(bit_reverse(tag & (sz - 1)));
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= n);
return l == r ? e() : prod_rec(l, r, 1, 0, sz);
}
private:
int index(int val) const { return val & (sz * 2 - 1); }
int bit_reverse(int val) const {
int res = 0;
for (int bit = 0; bit < log; bit++) {
res = (res << 1) | (val & 1);
val >>= 1;
}
return res;
}
void apply(int u, int tag) {
if (u < sz) {
lz[u] = tag;
}
prd[u] = pw[index(tag - len[u])];
}
void push(int u) {
if (u >= sz || lz[u] == -1) {
return;
}
apply(u << 1, lz[u]);
apply(u << 1 | 1, lz[u]);
lz[u] = -1;
}
void propagate_path(int pos) {
pos += sz;
for (int h = log; h >= 1; h--) {
push(pos >> h);
}
}
void assign_rec(int l, int r, int tag, int u, int low, int hi) {
if (hi <= l || r <= low) {
return;
}
if (l <= low && hi <= r) {
apply(u, tag);
return;
}
push(u);
int mid = (low + hi) / 2;
assign_rec(l, r, tag, u << 1, low, mid);
assign_rec(l, r, tag, u << 1 | 1, mid, hi);
prd[u] = op(prd[u << 1], prd[u << 1 | 1]);
}
S prod_rec(int l, int r, int u, int low, int hi) {
if (l <= low && hi <= r) {
return prd[u];
}
push(u);
int mid = (low + hi) / 2;
if (r <= mid) {
return prod_rec(l, r, u << 1, low, mid);
}
if (mid <= l) {
return prod_rec(l, r, u << 1 | 1, mid, hi);
}
return op(prod_rec(l, r, u << 1, low, mid),
prod_rec(l, r, u << 1 | 1, mid, hi));
}
};
} // namespace noya
#ifndef NOYA_RANGE_SET_RANGE_PRODUCT_HPP
#define NOYA_RANGE_SET_RANGE_PRODUCT_HPP 1
/// @complexity Time: O(n) construction and O(log n) per range assignment or
/// ordered range product.
/// Space: O(n).
#include <algorithm>
#include <cassert>
#include <vector>
namespace noya {
/// @brief Segment tree for assigning one value to a range and taking an
/// ordered monoid product. For every assigned value, powers for all segment
/// lengths are cached in a circular table. Lazy nodes refer to those cached
/// powers, so a full-cover assignment is constant time and no idempotence or
/// commutativity is required from the monoid.
template <class S, auto op, auto e> struct range_set_range_product {
int n = 0;
int sz = 1;
int log = 0;
int ptr = 0;
std::vector<int> lz;
std::vector<int> len;
std::vector<S> pw;
std::vector<S> prd;
range_set_range_product() = default;
explicit range_set_range_product(const std::vector<S> &a) {
build(a);
}
void build(const std::vector<S> &a) {
n = int(a.size());
sz = 1;
log = 0;
while (sz < std::max(1, n)) {
sz <<= 1;
log++;
}
ptr = 0;
lz.assign(sz, -1);
len.assign(sz * 2, sz);
for (int u = sz - 1; u >= 1; u--) {
len[u] = len[u << 1] >> 1;
}
pw.assign(sz * 2, e());
prd.assign(sz * 2, e());
for (int i = 0; i < n; i++) {
prd[sz + i] = a[i];
}
for (int u = sz - 1; u >= 1; u--) {
prd[u] = op(prd[u << 1], prd[u << 1 | 1]);
}
}
void assign(int l, int r, S val) {
assert(0 <= l && l <= r && r <= n);
if (l == r) {
return;
}
int tag = ptr++;
if (ptr == sz * 2) {
ptr = 0;
}
pw[index(tag - sz)] = val;
for (int h = 1; h <= log; h++) {
val = op(val, val);
pw[index(tag - (sz >> h))] = val;
}
assign_rec(l, r, tag, 1, 0, sz);
propagate_path(bit_reverse(tag & (sz - 1)));
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= n);
return l == r ? e() : prod_rec(l, r, 1, 0, sz);
}
private:
int index(int val) const { return val & (sz * 2 - 1); }
int bit_reverse(int val) const {
int res = 0;
for (int bit = 0; bit < log; bit++) {
res = (res << 1) | (val & 1);
val >>= 1;
}
return res;
}
void apply(int u, int tag) {
if (u < sz) {
lz[u] = tag;
}
prd[u] = pw[index(tag - len[u])];
}
void push(int u) {
if (u >= sz || lz[u] == -1) {
return;
}
apply(u << 1, lz[u]);
apply(u << 1 | 1, lz[u]);
lz[u] = -1;
}
void propagate_path(int pos) {
pos += sz;
for (int h = log; h >= 1; h--) {
push(pos >> h);
}
}
void assign_rec(int l, int r, int tag, int u, int low, int hi) {
if (hi <= l || r <= low) {
return;
}
if (l <= low && hi <= r) {
apply(u, tag);
return;
}
push(u);
int mid = (low + hi) / 2;
assign_rec(l, r, tag, u << 1, low, mid);
assign_rec(l, r, tag, u << 1 | 1, mid, hi);
prd[u] = op(prd[u << 1], prd[u << 1 | 1]);
}
S prod_rec(int l, int r, int u, int low, int hi) {
if (l <= low && hi <= r) {
return prd[u];
}
push(u);
int mid = (low + hi) / 2;
if (r <= mid) {
return prod_rec(l, r, u << 1, low, mid);
}
if (mid <= l) {
return prod_rec(l, r, u << 1 | 1, mid, hi);
}
return op(prod_rec(l, r, u << 1, low, mid),
prod_rec(l, r, u << 1 | 1, mid, hi));
}
};
} // namespace noya
#endif // NOYA_RANGE_SET_RANGE_PRODUCT_HPP
#include <algorithm>
#include <cassert>
#include <vector>
/// @complexity Time: O(n) construction and O(log n) per range assignment or
/// ordered range product.
/// Space: O(n).
namespace noya {
/// @brief Segment tree for assigning one value to a range and taking an
/// ordered monoid product. For every assigned value, powers for all segment
/// lengths are cached in a circular table. Lazy nodes refer to those cached
/// powers, so a full-cover assignment is constant time and no idempotence or
/// commutativity is required from the monoid.
template <class S, auto op, auto e> struct range_set_range_product {
int n = 0;
int sz = 1;
int log = 0;
int ptr = 0;
std::vector<int> lz;
std::vector<int> len;
std::vector<S> pw;
std::vector<S> prd;
range_set_range_product() = default;
explicit range_set_range_product(const std::vector<S> &a) {
build(a);
}
void build(const std::vector<S> &a) {
n = int(a.size());
sz = 1;
log = 0;
while (sz < std::max(1, n)) {
sz <<= 1;
log++;
}
ptr = 0;
lz.assign(sz, -1);
len.assign(sz * 2, sz);
for (int u = sz - 1; u >= 1; u--) {
len[u] = len[u << 1] >> 1;
}
pw.assign(sz * 2, e());
prd.assign(sz * 2, e());
for (int i = 0; i < n; i++) {
prd[sz + i] = a[i];
}
for (int u = sz - 1; u >= 1; u--) {
prd[u] = op(prd[u << 1], prd[u << 1 | 1]);
}
}
void assign(int l, int r, S val) {
assert(0 <= l && l <= r && r <= n);
if (l == r) {
return;
}
int tag = ptr++;
if (ptr == sz * 2) {
ptr = 0;
}
pw[index(tag - sz)] = val;
for (int h = 1; h <= log; h++) {
val = op(val, val);
pw[index(tag - (sz >> h))] = val;
}
assign_rec(l, r, tag, 1, 0, sz);
propagate_path(bit_reverse(tag & (sz - 1)));
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= n);
return l == r ? e() : prod_rec(l, r, 1, 0, sz);
}
private:
int index(int val) const { return val & (sz * 2 - 1); }
int bit_reverse(int val) const {
int res = 0;
for (int bit = 0; bit < log; bit++) {
res = (res << 1) | (val & 1);
val >>= 1;
}
return res;
}
void apply(int u, int tag) {
if (u < sz) {
lz[u] = tag;
}
prd[u] = pw[index(tag - len[u])];
}
void push(int u) {
if (u >= sz || lz[u] == -1) {
return;
}
apply(u << 1, lz[u]);
apply(u << 1 | 1, lz[u]);
lz[u] = -1;
}
void propagate_path(int pos) {
pos += sz;
for (int h = log; h >= 1; h--) {
push(pos >> h);
}
}
void assign_rec(int l, int r, int tag, int u, int low, int hi) {
if (hi <= l || r <= low) {
return;
}
if (l <= low && hi <= r) {
apply(u, tag);
return;
}
push(u);
int mid = (low + hi) / 2;
assign_rec(l, r, tag, u << 1, low, mid);
assign_rec(l, r, tag, u << 1 | 1, mid, hi);
prd[u] = op(prd[u << 1], prd[u << 1 | 1]);
}
S prod_rec(int l, int r, int u, int low, int hi) {
if (l <= low && hi <= r) {
return prd[u];
}
push(u);
int mid = (low + hi) / 2;
if (r <= mid) {
return prod_rec(l, r, u << 1, low, mid);
}
if (mid <= l) {
return prod_rec(l, r, u << 1 | 1, mid, hi);
}
return op(prod_rec(l, r, u << 1, low, mid),
prod_rec(l, r, u << 1 | 1, mid, hi));
}
};
} // namespace noya