segment_tree_beats.hpp¶
维护区间 chmin、chmax、加法与区间和/最值;适合普通懒标记无法直接表示的截断更新。
Complexity: Time: O(n) build; amortized O(log^2 n) chmin/chmax and O(log n) add/query. Space: O(n).
AC 记录:range_add_range_min, range_chmin_chmax_add_range_sum。
Implementation¶
当前头文件,省略 include guard;依赖见 #include。
/// @complexity Time: O(n) build; amortized O(log^2 n) chmin/chmax and O(log n) add/query.
/// Space: O(n).
#include <algorithm>
#include <cassert>
#include <limits>
#include <vector>
namespace noya {
/// @brief Segment Tree Beats supporting range add, chmin, chmax, sum, minimum,
/// and maximum queries; bound updates run in amortized O(log^2 n) time.
template <class T> struct segment_tree_beats {
struct node {
// mx/mn: extrema; mx2/mn2: strict second extrema; cmx/cmn: multiplicities.
T sum{};
T mx{};
T mx2{};
T mn{};
T mn2{};
T add{};
int cmx = 0;
int cmn = 0;
int len = 0;
bool hmx = false;
bool hmn = false;
};
int n = 0;
std::vector<node> tr;
segment_tree_beats() = default;
explicit segment_tree_beats(const std::vector<T> &a) { build(a); }
/// @brief Rebuild from array a in O(n) time.
void build(const std::vector<T> &a) {
n = int(a.size());
tr.assign(std::max(1, 4 * n), {});
if (n > 0) {
build_at(1, 0, n, a);
}
}
/// @brief Add x to every element of [l, r).
void range_add(int l, int r, const T &x) {
check_range(l, r);
if (l < r) {
range_add_at(1, 0, n, l, r, x);
}
}
/// @brief Replace each x in [l, r) by min(x, hi).
void range_chmin(int l, int r, const T &hi) {
check_range(l, r);
if (l < r) {
range_chmin_at(1, 0, n, l, r, hi);
}
}
/// @brief Replace each x in [l, r) by max(x, lo).
void range_chmax(int l, int r, const T &lo) {
check_range(l, r);
if (l < r) {
range_chmax_at(1, 0, n, l, r, lo);
}
}
/// @brief Return the sum over [l, r); an empty range has sum zero.
T range_sum(int l, int r) {
check_range(l, r);
return l == r ? T{} : range_sum_at(1, 0, n, l, r);
}
/// @brief Return the minimum over the nonempty range [l, r).
T range_min(int l, int r) {
check_nonempty_range(l, r);
return range_min_at(1, 0, n, l, r);
}
/// @brief Return the maximum over the nonempty range [l, r).
T range_max(int l, int r) {
check_nonempty_range(l, r);
return range_max_at(1, 0, n, l, r);
}
/// @brief Return the sum of the entire array.
T all_sum() const { return n == 0 ? T{} : tr[1].sum; }
/// @brief Return the minimum of the nonempty array.
T all_min() const {
assert(n > 0);
return tr[1].mn;
}
/// @brief Return the maximum of the nonempty array.
T all_max() const {
assert(n > 0);
return tr[1].mx;
}
private:
void check_range(int l, int r) const { assert(0 <= l && l <= r && r <= n); }
void check_nonempty_range(int l, int r) const {
check_range(l, r);
assert(l < r);
}
static node leaf(const T &x) {
node res;
res.sum = res.mx = res.mn = x;
res.cmx = res.cmn = res.len = 1;
return res;
}
static void assign_maximum(node &res, const node &l, const node &r) {
if (l.mx == r.mx) {
res.mx = l.mx;
res.cmx = l.cmx + r.cmx;
if (l.hmx && r.hmx) {
res.mx2 = std::max(l.mx2, r.mx2);
res.hmx = true;
} else if (l.hmx) {
res.mx2 = l.mx2;
res.hmx = true;
} else if (r.hmx) {
res.mx2 = r.mx2;
res.hmx = true;
}
return;
}
const node &hi = l.mx > r.mx ? l : r;
const node &lo = l.mx > r.mx ? r : l;
res.mx = hi.mx;
res.cmx = hi.cmx;
res.mx2 = hi.hmx ? std::max(hi.mx2, lo.mx) : lo.mx;
res.hmx = true;
}
static void assign_minimum(node &res, const node &l, const node &r) {
if (l.mn == r.mn) {
res.mn = l.mn;
res.cmn = l.cmn + r.cmn;
if (l.hmn && r.hmn) {
res.mn2 = std::min(l.mn2, r.mn2);
res.hmn = true;
} else if (l.hmn) {
res.mn2 = l.mn2;
res.hmn = true;
} else if (r.hmn) {
res.mn2 = r.mn2;
res.hmn = true;
}
return;
}
const node &lo = l.mn < r.mn ? l : r;
const node &hi = l.mn < r.mn ? r : l;
res.mn = lo.mn;
res.cmn = lo.cmn;
res.mn2 = lo.hmn ? std::min(lo.mn2, hi.mn) : hi.mn;
res.hmn = true;
}
static node merge_nodes(const node &l, const node &r) {
node res;
res.sum = l.sum + r.sum;
res.len = l.len + r.len;
assign_maximum(res, l, r);
assign_minimum(res, l, r);
return res;
}
void build_at(int id, int l, int r, const std::vector<T> &a) {
if (r - l == 1) {
tr[id] = leaf(a[l]);
return;
}
int m = (l + r) / 2;
build_at(id * 2, l, m, a);
build_at(id * 2 + 1, m, r, a);
pull(id);
}
void pull(int id) { tr[id] = merge_nodes(tr[id * 2], tr[id * 2 + 1]); }
void apply_add(int id, const T &x) {
node &u = tr[id];
u.sum += x * u.len;
u.mx += x;
u.mn += x;
if (u.hmx) {
u.mx2 += x;
}
if (u.hmn) {
u.mn2 += x;
}
u.add += x;
}
void apply_chmin(int id, const T &hi) {
node &u = tr[id];
if (u.mx <= hi) {
return;
}
T old = u.mx;
u.sum += (hi - old) * u.cmx;
if (u.mn == old) {
u.mn = hi;
} else if (u.hmn && u.mn2 == old) {
u.mn2 = hi;
}
u.mx = hi;
}
void apply_chmax(int id, const T &lo) {
node &u = tr[id];
if (lo <= u.mn) {
return;
}
T old = u.mn;
u.sum += (lo - old) * u.cmn;
if (u.mx == old) {
u.mx = lo;
} else if (u.hmx && u.mx2 == old) {
u.mx2 = lo;
}
u.mn = lo;
}
void push(int id) {
node &u = tr[id];
if (u.len == 1) {
u.add = T{};
return;
}
if (u.add != T{}) {
apply_add(id * 2, u.add);
apply_add(id * 2 + 1, u.add);
u.add = T{};
}
if (tr[id * 2].mx > u.mx) {
apply_chmin(id * 2, u.mx);
}
if (tr[id * 2 + 1].mx > u.mx) {
apply_chmin(id * 2 + 1, u.mx);
}
if (tr[id * 2].mn < u.mn) {
apply_chmax(id * 2, u.mn);
}
if (tr[id * 2 + 1].mn < u.mn) {
apply_chmax(id * 2 + 1, u.mn);
}
}
void range_add_at(int id, int l, int r, int ql, int qr, const T &x) {
if (qr <= l || r <= ql) {
return;
}
if (ql <= l && r <= qr) {
apply_add(id, x);
return;
}
push(id);
int m = (l + r) / 2;
range_add_at(id * 2, l, m, ql, qr, x);
range_add_at(id * 2 + 1, m, r, ql, qr, x);
pull(id);
}
void range_chmin_at(int id, int l, int r, int ql, int qr, const T &hi) {
node &u = tr[id];
if (qr <= l || r <= ql || u.mx <= hi) {
return;
}
if (ql <= l && r <= qr && (!u.hmx || u.mx2 < hi)) {
apply_chmin(id, hi);
return;
}
push(id);
int m = (l + r) / 2;
range_chmin_at(id * 2, l, m, ql, qr, hi);
range_chmin_at(id * 2 + 1, m, r, ql, qr, hi);
pull(id);
}
void range_chmax_at(int id, int l, int r, int ql, int qr, const T &lo) {
node &u = tr[id];
if (qr <= l || r <= ql || lo <= u.mn) {
return;
}
if (ql <= l && r <= qr && (!u.hmn || lo < u.mn2)) {
apply_chmax(id, lo);
return;
}
push(id);
int m = (l + r) / 2;
range_chmax_at(id * 2, l, m, ql, qr, lo);
range_chmax_at(id * 2 + 1, m, r, ql, qr, lo);
pull(id);
}
T range_sum_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].sum;
}
push(id);
int m = (l + r) / 2;
T res{};
if (ql < m) {
res += range_sum_at(id * 2, l, m, ql, qr);
}
if (m < qr) {
res += range_sum_at(id * 2 + 1, m, r, ql, qr);
}
return res;
}
T range_min_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].mn;
}
push(id);
int m = (l + r) / 2;
T res = std::numeric_limits<T>::max();
if (ql < m) {
res = std::min(res, range_min_at(id * 2, l, m, ql, qr));
}
if (m < qr) {
res = std::min(res, range_min_at(id * 2 + 1, m, r, ql, qr));
}
return res;
}
T range_max_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].mx;
}
push(id);
int m = (l + r) / 2;
T res = std::numeric_limits<T>::lowest();
if (ql < m) {
res = std::max(res, range_max_at(id * 2, l, m, ql, qr));
}
if (m < qr) {
res = std::max(res, range_max_at(id * 2 + 1, m, r, ql, qr));
}
return res;
}
};
} // namespace noya
#ifndef NOYA_SEGMENT_TREE_BEATS_HPP
#define NOYA_SEGMENT_TREE_BEATS_HPP 1
/// @complexity Time: O(n) build; amortized O(log^2 n) chmin/chmax and O(log n) add/query.
/// Space: O(n).
#include <algorithm>
#include <cassert>
#include <limits>
#include <vector>
namespace noya {
/// @brief Segment Tree Beats supporting range add, chmin, chmax, sum, minimum,
/// and maximum queries; bound updates run in amortized O(log^2 n) time.
template <class T> struct segment_tree_beats {
struct node {
// mx/mn: extrema; mx2/mn2: strict second extrema; cmx/cmn: multiplicities.
T sum{};
T mx{};
T mx2{};
T mn{};
T mn2{};
T add{};
int cmx = 0;
int cmn = 0;
int len = 0;
bool hmx = false;
bool hmn = false;
};
int n = 0;
std::vector<node> tr;
segment_tree_beats() = default;
explicit segment_tree_beats(const std::vector<T> &a) { build(a); }
/// @brief Rebuild from array a in O(n) time.
void build(const std::vector<T> &a) {
n = int(a.size());
tr.assign(std::max(1, 4 * n), {});
if (n > 0) {
build_at(1, 0, n, a);
}
}
/// @brief Add x to every element of [l, r).
void range_add(int l, int r, const T &x) {
check_range(l, r);
if (l < r) {
range_add_at(1, 0, n, l, r, x);
}
}
/// @brief Replace each x in [l, r) by min(x, hi).
void range_chmin(int l, int r, const T &hi) {
check_range(l, r);
if (l < r) {
range_chmin_at(1, 0, n, l, r, hi);
}
}
/// @brief Replace each x in [l, r) by max(x, lo).
void range_chmax(int l, int r, const T &lo) {
check_range(l, r);
if (l < r) {
range_chmax_at(1, 0, n, l, r, lo);
}
}
/// @brief Return the sum over [l, r); an empty range has sum zero.
T range_sum(int l, int r) {
check_range(l, r);
return l == r ? T{} : range_sum_at(1, 0, n, l, r);
}
/// @brief Return the minimum over the nonempty range [l, r).
T range_min(int l, int r) {
check_nonempty_range(l, r);
return range_min_at(1, 0, n, l, r);
}
/// @brief Return the maximum over the nonempty range [l, r).
T range_max(int l, int r) {
check_nonempty_range(l, r);
return range_max_at(1, 0, n, l, r);
}
/// @brief Return the sum of the entire array.
T all_sum() const { return n == 0 ? T{} : tr[1].sum; }
/// @brief Return the minimum of the nonempty array.
T all_min() const {
assert(n > 0);
return tr[1].mn;
}
/// @brief Return the maximum of the nonempty array.
T all_max() const {
assert(n > 0);
return tr[1].mx;
}
private:
void check_range(int l, int r) const { assert(0 <= l && l <= r && r <= n); }
void check_nonempty_range(int l, int r) const {
check_range(l, r);
assert(l < r);
}
static node leaf(const T &x) {
node res;
res.sum = res.mx = res.mn = x;
res.cmx = res.cmn = res.len = 1;
return res;
}
static void assign_maximum(node &res, const node &l, const node &r) {
if (l.mx == r.mx) {
res.mx = l.mx;
res.cmx = l.cmx + r.cmx;
if (l.hmx && r.hmx) {
res.mx2 = std::max(l.mx2, r.mx2);
res.hmx = true;
} else if (l.hmx) {
res.mx2 = l.mx2;
res.hmx = true;
} else if (r.hmx) {
res.mx2 = r.mx2;
res.hmx = true;
}
return;
}
const node &hi = l.mx > r.mx ? l : r;
const node &lo = l.mx > r.mx ? r : l;
res.mx = hi.mx;
res.cmx = hi.cmx;
res.mx2 = hi.hmx ? std::max(hi.mx2, lo.mx) : lo.mx;
res.hmx = true;
}
static void assign_minimum(node &res, const node &l, const node &r) {
if (l.mn == r.mn) {
res.mn = l.mn;
res.cmn = l.cmn + r.cmn;
if (l.hmn && r.hmn) {
res.mn2 = std::min(l.mn2, r.mn2);
res.hmn = true;
} else if (l.hmn) {
res.mn2 = l.mn2;
res.hmn = true;
} else if (r.hmn) {
res.mn2 = r.mn2;
res.hmn = true;
}
return;
}
const node &lo = l.mn < r.mn ? l : r;
const node &hi = l.mn < r.mn ? r : l;
res.mn = lo.mn;
res.cmn = lo.cmn;
res.mn2 = lo.hmn ? std::min(lo.mn2, hi.mn) : hi.mn;
res.hmn = true;
}
static node merge_nodes(const node &l, const node &r) {
node res;
res.sum = l.sum + r.sum;
res.len = l.len + r.len;
assign_maximum(res, l, r);
assign_minimum(res, l, r);
return res;
}
void build_at(int id, int l, int r, const std::vector<T> &a) {
if (r - l == 1) {
tr[id] = leaf(a[l]);
return;
}
int m = (l + r) / 2;
build_at(id * 2, l, m, a);
build_at(id * 2 + 1, m, r, a);
pull(id);
}
void pull(int id) { tr[id] = merge_nodes(tr[id * 2], tr[id * 2 + 1]); }
void apply_add(int id, const T &x) {
node &u = tr[id];
u.sum += x * u.len;
u.mx += x;
u.mn += x;
if (u.hmx) {
u.mx2 += x;
}
if (u.hmn) {
u.mn2 += x;
}
u.add += x;
}
void apply_chmin(int id, const T &hi) {
node &u = tr[id];
if (u.mx <= hi) {
return;
}
T old = u.mx;
u.sum += (hi - old) * u.cmx;
if (u.mn == old) {
u.mn = hi;
} else if (u.hmn && u.mn2 == old) {
u.mn2 = hi;
}
u.mx = hi;
}
void apply_chmax(int id, const T &lo) {
node &u = tr[id];
if (lo <= u.mn) {
return;
}
T old = u.mn;
u.sum += (lo - old) * u.cmn;
if (u.mx == old) {
u.mx = lo;
} else if (u.hmx && u.mx2 == old) {
u.mx2 = lo;
}
u.mn = lo;
}
void push(int id) {
node &u = tr[id];
if (u.len == 1) {
u.add = T{};
return;
}
if (u.add != T{}) {
apply_add(id * 2, u.add);
apply_add(id * 2 + 1, u.add);
u.add = T{};
}
if (tr[id * 2].mx > u.mx) {
apply_chmin(id * 2, u.mx);
}
if (tr[id * 2 + 1].mx > u.mx) {
apply_chmin(id * 2 + 1, u.mx);
}
if (tr[id * 2].mn < u.mn) {
apply_chmax(id * 2, u.mn);
}
if (tr[id * 2 + 1].mn < u.mn) {
apply_chmax(id * 2 + 1, u.mn);
}
}
void range_add_at(int id, int l, int r, int ql, int qr, const T &x) {
if (qr <= l || r <= ql) {
return;
}
if (ql <= l && r <= qr) {
apply_add(id, x);
return;
}
push(id);
int m = (l + r) / 2;
range_add_at(id * 2, l, m, ql, qr, x);
range_add_at(id * 2 + 1, m, r, ql, qr, x);
pull(id);
}
void range_chmin_at(int id, int l, int r, int ql, int qr, const T &hi) {
node &u = tr[id];
if (qr <= l || r <= ql || u.mx <= hi) {
return;
}
if (ql <= l && r <= qr && (!u.hmx || u.mx2 < hi)) {
apply_chmin(id, hi);
return;
}
push(id);
int m = (l + r) / 2;
range_chmin_at(id * 2, l, m, ql, qr, hi);
range_chmin_at(id * 2 + 1, m, r, ql, qr, hi);
pull(id);
}
void range_chmax_at(int id, int l, int r, int ql, int qr, const T &lo) {
node &u = tr[id];
if (qr <= l || r <= ql || lo <= u.mn) {
return;
}
if (ql <= l && r <= qr && (!u.hmn || lo < u.mn2)) {
apply_chmax(id, lo);
return;
}
push(id);
int m = (l + r) / 2;
range_chmax_at(id * 2, l, m, ql, qr, lo);
range_chmax_at(id * 2 + 1, m, r, ql, qr, lo);
pull(id);
}
T range_sum_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].sum;
}
push(id);
int m = (l + r) / 2;
T res{};
if (ql < m) {
res += range_sum_at(id * 2, l, m, ql, qr);
}
if (m < qr) {
res += range_sum_at(id * 2 + 1, m, r, ql, qr);
}
return res;
}
T range_min_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].mn;
}
push(id);
int m = (l + r) / 2;
T res = std::numeric_limits<T>::max();
if (ql < m) {
res = std::min(res, range_min_at(id * 2, l, m, ql, qr));
}
if (m < qr) {
res = std::min(res, range_min_at(id * 2 + 1, m, r, ql, qr));
}
return res;
}
T range_max_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].mx;
}
push(id);
int m = (l + r) / 2;
T res = std::numeric_limits<T>::lowest();
if (ql < m) {
res = std::max(res, range_max_at(id * 2, l, m, ql, qr));
}
if (m < qr) {
res = std::max(res, range_max_at(id * 2 + 1, m, r, ql, qr));
}
return res;
}
};
} // namespace noya
#endif // NOYA_SEGMENT_TREE_BEATS_HPP
#include <algorithm>
#include <cassert>
#include <limits>
#include <vector>
/// @complexity Time: O(n) build; amortized O(log^2 n) chmin/chmax and O(log n) add/query.
/// Space: O(n).
namespace noya {
/// @brief Segment Tree Beats supporting range add, chmin, chmax, sum, minimum,
/// and maximum queries; bound updates run in amortized O(log^2 n) time.
template <class T> struct segment_tree_beats {
struct node {
// mx/mn: extrema; mx2/mn2: strict second extrema; cmx/cmn: multiplicities.
T sum{};
T mx{};
T mx2{};
T mn{};
T mn2{};
T add{};
int cmx = 0;
int cmn = 0;
int len = 0;
bool hmx = false;
bool hmn = false;
};
int n = 0;
std::vector<node> tr;
segment_tree_beats() = default;
explicit segment_tree_beats(const std::vector<T> &a) { build(a); }
/// @brief Rebuild from array a in O(n) time.
void build(const std::vector<T> &a) {
n = int(a.size());
tr.assign(std::max(1, 4 * n), {});
if (n > 0) {
build_at(1, 0, n, a);
}
}
/// @brief Add x to every element of [l, r).
void range_add(int l, int r, const T &x) {
check_range(l, r);
if (l < r) {
range_add_at(1, 0, n, l, r, x);
}
}
/// @brief Replace each x in [l, r) by min(x, hi).
void range_chmin(int l, int r, const T &hi) {
check_range(l, r);
if (l < r) {
range_chmin_at(1, 0, n, l, r, hi);
}
}
/// @brief Replace each x in [l, r) by max(x, lo).
void range_chmax(int l, int r, const T &lo) {
check_range(l, r);
if (l < r) {
range_chmax_at(1, 0, n, l, r, lo);
}
}
/// @brief Return the sum over [l, r); an empty range has sum zero.
T range_sum(int l, int r) {
check_range(l, r);
return l == r ? T{} : range_sum_at(1, 0, n, l, r);
}
/// @brief Return the minimum over the nonempty range [l, r).
T range_min(int l, int r) {
check_nonempty_range(l, r);
return range_min_at(1, 0, n, l, r);
}
/// @brief Return the maximum over the nonempty range [l, r).
T range_max(int l, int r) {
check_nonempty_range(l, r);
return range_max_at(1, 0, n, l, r);
}
/// @brief Return the sum of the entire array.
T all_sum() const { return n == 0 ? T{} : tr[1].sum; }
/// @brief Return the minimum of the nonempty array.
T all_min() const {
assert(n > 0);
return tr[1].mn;
}
/// @brief Return the maximum of the nonempty array.
T all_max() const {
assert(n > 0);
return tr[1].mx;
}
private:
void check_range(int l, int r) const { assert(0 <= l && l <= r && r <= n); }
void check_nonempty_range(int l, int r) const {
check_range(l, r);
assert(l < r);
}
static node leaf(const T &x) {
node res;
res.sum = res.mx = res.mn = x;
res.cmx = res.cmn = res.len = 1;
return res;
}
static void assign_maximum(node &res, const node &l, const node &r) {
if (l.mx == r.mx) {
res.mx = l.mx;
res.cmx = l.cmx + r.cmx;
if (l.hmx && r.hmx) {
res.mx2 = std::max(l.mx2, r.mx2);
res.hmx = true;
} else if (l.hmx) {
res.mx2 = l.mx2;
res.hmx = true;
} else if (r.hmx) {
res.mx2 = r.mx2;
res.hmx = true;
}
return;
}
const node &hi = l.mx > r.mx ? l : r;
const node &lo = l.mx > r.mx ? r : l;
res.mx = hi.mx;
res.cmx = hi.cmx;
res.mx2 = hi.hmx ? std::max(hi.mx2, lo.mx) : lo.mx;
res.hmx = true;
}
static void assign_minimum(node &res, const node &l, const node &r) {
if (l.mn == r.mn) {
res.mn = l.mn;
res.cmn = l.cmn + r.cmn;
if (l.hmn && r.hmn) {
res.mn2 = std::min(l.mn2, r.mn2);
res.hmn = true;
} else if (l.hmn) {
res.mn2 = l.mn2;
res.hmn = true;
} else if (r.hmn) {
res.mn2 = r.mn2;
res.hmn = true;
}
return;
}
const node &lo = l.mn < r.mn ? l : r;
const node &hi = l.mn < r.mn ? r : l;
res.mn = lo.mn;
res.cmn = lo.cmn;
res.mn2 = lo.hmn ? std::min(lo.mn2, hi.mn) : hi.mn;
res.hmn = true;
}
static node merge_nodes(const node &l, const node &r) {
node res;
res.sum = l.sum + r.sum;
res.len = l.len + r.len;
assign_maximum(res, l, r);
assign_minimum(res, l, r);
return res;
}
void build_at(int id, int l, int r, const std::vector<T> &a) {
if (r - l == 1) {
tr[id] = leaf(a[l]);
return;
}
int m = (l + r) / 2;
build_at(id * 2, l, m, a);
build_at(id * 2 + 1, m, r, a);
pull(id);
}
void pull(int id) { tr[id] = merge_nodes(tr[id * 2], tr[id * 2 + 1]); }
void apply_add(int id, const T &x) {
node &u = tr[id];
u.sum += x * u.len;
u.mx += x;
u.mn += x;
if (u.hmx) {
u.mx2 += x;
}
if (u.hmn) {
u.mn2 += x;
}
u.add += x;
}
void apply_chmin(int id, const T &hi) {
node &u = tr[id];
if (u.mx <= hi) {
return;
}
T old = u.mx;
u.sum += (hi - old) * u.cmx;
if (u.mn == old) {
u.mn = hi;
} else if (u.hmn && u.mn2 == old) {
u.mn2 = hi;
}
u.mx = hi;
}
void apply_chmax(int id, const T &lo) {
node &u = tr[id];
if (lo <= u.mn) {
return;
}
T old = u.mn;
u.sum += (lo - old) * u.cmn;
if (u.mx == old) {
u.mx = lo;
} else if (u.hmx && u.mx2 == old) {
u.mx2 = lo;
}
u.mn = lo;
}
void push(int id) {
node &u = tr[id];
if (u.len == 1) {
u.add = T{};
return;
}
if (u.add != T{}) {
apply_add(id * 2, u.add);
apply_add(id * 2 + 1, u.add);
u.add = T{};
}
if (tr[id * 2].mx > u.mx) {
apply_chmin(id * 2, u.mx);
}
if (tr[id * 2 + 1].mx > u.mx) {
apply_chmin(id * 2 + 1, u.mx);
}
if (tr[id * 2].mn < u.mn) {
apply_chmax(id * 2, u.mn);
}
if (tr[id * 2 + 1].mn < u.mn) {
apply_chmax(id * 2 + 1, u.mn);
}
}
void range_add_at(int id, int l, int r, int ql, int qr, const T &x) {
if (qr <= l || r <= ql) {
return;
}
if (ql <= l && r <= qr) {
apply_add(id, x);
return;
}
push(id);
int m = (l + r) / 2;
range_add_at(id * 2, l, m, ql, qr, x);
range_add_at(id * 2 + 1, m, r, ql, qr, x);
pull(id);
}
void range_chmin_at(int id, int l, int r, int ql, int qr, const T &hi) {
node &u = tr[id];
if (qr <= l || r <= ql || u.mx <= hi) {
return;
}
if (ql <= l && r <= qr && (!u.hmx || u.mx2 < hi)) {
apply_chmin(id, hi);
return;
}
push(id);
int m = (l + r) / 2;
range_chmin_at(id * 2, l, m, ql, qr, hi);
range_chmin_at(id * 2 + 1, m, r, ql, qr, hi);
pull(id);
}
void range_chmax_at(int id, int l, int r, int ql, int qr, const T &lo) {
node &u = tr[id];
if (qr <= l || r <= ql || lo <= u.mn) {
return;
}
if (ql <= l && r <= qr && (!u.hmn || lo < u.mn2)) {
apply_chmax(id, lo);
return;
}
push(id);
int m = (l + r) / 2;
range_chmax_at(id * 2, l, m, ql, qr, lo);
range_chmax_at(id * 2 + 1, m, r, ql, qr, lo);
pull(id);
}
T range_sum_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].sum;
}
push(id);
int m = (l + r) / 2;
T res{};
if (ql < m) {
res += range_sum_at(id * 2, l, m, ql, qr);
}
if (m < qr) {
res += range_sum_at(id * 2 + 1, m, r, ql, qr);
}
return res;
}
T range_min_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].mn;
}
push(id);
int m = (l + r) / 2;
T res = std::numeric_limits<T>::max();
if (ql < m) {
res = std::min(res, range_min_at(id * 2, l, m, ql, qr));
}
if (m < qr) {
res = std::min(res, range_min_at(id * 2 + 1, m, r, ql, qr));
}
return res;
}
T range_max_at(int id, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[id].mx;
}
push(id);
int m = (l + r) / 2;
T res = std::numeric_limits<T>::lowest();
if (ql < m) {
res = std::max(res, range_max_at(id * 2, l, m, ql, qr));
}
if (m < qr) {
res = std::max(res, range_max_at(id * 2 + 1, m, r, ql, qr));
}
return res;
}
};
} // namespace noya