From 6ca8e25f0e0bc4b09edd15e7b7e552b1d1f4e02c Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Sun, 26 Oct 2025 13:49:19 +0900 Subject: [PATCH 1/2] refactor beats --- segmenttree/acl_beats.hpp | 95 -------------- segmenttree/test/beats.test.cpp | 18 ++- segmenttree/test/beats_random_test.test.cpp | 20 ++- .../trees/range-chmin-chmax-add-range-sum.hpp | 122 ++++++++++++++++++ 4 files changed, 142 insertions(+), 113 deletions(-) create mode 100644 segmenttree/trees/range-chmin-chmax-add-range-sum.hpp diff --git a/segmenttree/acl_beats.hpp b/segmenttree/acl_beats.hpp index ef5b9dfc..e0ec4d3c 100644 --- a/segmenttree/acl_beats.hpp +++ b/segmenttree/acl_beats.hpp @@ -1,9 +1,6 @@ #pragma once #include "acl_lazysegtree.hpp" -#include -#include - template class segtree_beats : public atcoder::lazy_segtree { using Base = atcoder::lazy_segtree; @@ -16,95 +13,3 @@ class segtree_beats : public atcoder::lazy_segtree inline Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { - assert(a <= a2); // a < a2 or a == a2 == INF - assert(c <= c2); // c < c2 or c == c2 == -INF - return a == c ? std::min(a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max(a, c); -} -template inline Num second_highest(Num a, Num a2, Num b, Num b2) noexcept { - assert(a >= a2); // a > a2 or a == a2 == -INF - assert(b >= b2); // b > b2 or b == b2 == INF - return a == b ? std::max(a2, b2) : a2 >= b ? a2 : b2 >= a ? b2 : std::min(a, b); -} - -using BNum = long long; -constexpr BNum BINF = 1LL << 61; - -struct S { - BNum lo, hi, lo2, hi2, sum; - unsigned sz, nlo, nhi; - bool fail; - S() : lo(BINF), hi(-BINF), lo2(BINF), hi2(-BINF), sum(0), sz(0), nlo(0), nhi(0), fail(0) {} - S(BNum x, unsigned sz_) - : lo(x), hi(x), lo2(BINF), hi2(-BINF), sum(x * sz_), sz(sz_), nlo(sz_), nhi(sz_), fail(0) {} - friend std::ostream &operator<<(std::ostream &os, const S s) { - return os << "[(" << s.lo << "x" << s.nlo << ", " << s.lo2 << ", " << s.hi2 << ", " << s.hi - << "x" << s.nhi << "), sz=" << s.sz << ", sum=" << s.sum << "]"; - } -}; - -S e() { return S(); } -S op(S l, S r) { - if (l.lo > l.hi) return r; - if (r.lo > r.hi) return l; - S ret; - ret.lo = std::min(l.lo, r.lo); - ret.hi = std::max(l.hi, r.hi); - ret.lo2 = second_lowest(l.lo, l.lo2, r.lo, r.lo2), - ret.hi2 = second_highest(l.hi, l.hi2, r.hi, r.hi2); - ret.sum = l.sum + r.sum; - ret.sz = l.sz + r.sz; - ret.nlo = l.nlo * (l.lo <= r.lo) + r.nlo * (r.lo <= l.lo); - ret.nhi = l.nhi * (l.hi >= r.hi) + r.nhi * (r.hi >= l.hi); - return ret; -} -struct F { - BNum lb, ub, bias; - F() : lb(-BINF), ub(BINF), bias(0) {} - F(BNum chmax_, BNum chmin_, BNum add) : lb(chmax_), ub(chmin_), bias(add) {} - static F chmin(BNum x) noexcept { return F(-BINF, x, BNum(0)); } - static F chmax(BNum x) noexcept { return F(x, BINF, BNum(0)); } - static F add(BNum x) noexcept { return F(-BINF, BINF, x); }; -}; - -F composition(F fnew, F fold) { - F ret; - ret.lb = std::max(std::min(fold.lb + fold.bias, fnew.ub), fnew.lb) - fold.bias; - ret.ub = std::min(std::max(fold.ub + fold.bias, fnew.lb), fnew.ub) - fold.bias; - ret.bias = fold.bias + fnew.bias; - return ret; -} -F id() { return F(); } -S mapping(F f, S x) { - if (x.sz == 0) return e(); - - // f の作用後 x の要素が 1 種類だけになるケース - if (x.lo == x.hi or f.lb == f.ub or f.lb >= x.hi or f.ub <= x.lo) { - return S(std::min(std::max(x.lo, f.lb), f.ub) + f.bias, x.sz); - } - - // 2 種類 -> 1 種類 - if (x.lo2 == x.hi) { - x.lo = x.hi2 = std::max(x.lo, f.lb) + f.bias; - x.hi = x.lo2 = std::min(x.hi, f.ub) + f.bias; - x.sum = x.lo * x.nlo + x.hi * x.nhi; - return x; - } - - // lo と lo2, hi と hi2 が潰れないケース - if (f.lb < x.lo2 and f.ub > x.hi2) { - BNum nxt_lo = std::max(x.lo, f.lb), nxt_hi = std::min(x.hi, f.ub); - x.sum += (nxt_lo - x.lo) * x.nlo - (x.hi - nxt_hi) * x.nhi + f.bias * x.sz; - x.lo = nxt_lo + f.bias, x.hi = nxt_hi + f.bias, x.lo2 += f.bias, x.hi2 += f.bias; - return x; - } - - x.fail = 1; - return x; -} - -using segtree = segtree_beats; - -} // namespace RangeChMinMaxAddSum diff --git a/segmenttree/test/beats.test.cpp b/segmenttree/test/beats.test.cpp index 15accbc3..93bab4bb 100644 --- a/segmenttree/test/beats.test.cpp +++ b/segmenttree/test/beats.test.cpp @@ -1,28 +1,32 @@ #define PROBLEM "https://judge.yosupo.jp/problem/range_chmin_chmax_add_range_sum" -#include "../acl_beats.hpp" +#include "../trees/range-chmin-chmax-add-range-sum.hpp" #include #include using namespace std; +using RCCARS = RangeChminChmaxAddRangeSum; + int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int N, Q; cin >> N >> Q; - vector A(N); + vector A(N); for (auto &a : A) { long long tmp; - cin >> tmp, a = {tmp, 1}; + cin >> tmp, a = RCCARS::Gen(tmp); } - RangeChMinMaxAddSum::segtree segtree(A); + + RCCARS::segtree segtree(A); + while (Q--) { int q, l, r; long long b; cin >> q >> l >> r; if (q < 3) { cin >> b; - if (q == 0) segtree.apply(l, r, RangeChMinMaxAddSum::F::chmin(b)); - if (q == 1) segtree.apply(l, r, RangeChMinMaxAddSum::F::chmax(b)); - if (q == 2) segtree.apply(l, r, RangeChMinMaxAddSum::F::add(b)); + if (q == 0) segtree.apply(l, r, RCCARS::Chmin(b)); + if (q == 1) segtree.apply(l, r, RCCARS::Chmax(b)); + if (q == 2) segtree.apply(l, r, RCCARS::Add(b)); } else { long long ret = segtree.prod(l, r).sum; cout << ret << '\n'; diff --git a/segmenttree/test/beats_random_test.test.cpp b/segmenttree/test/beats_random_test.test.cpp index d8fd33c9..5b1d03cf 100644 --- a/segmenttree/test/beats_random_test.test.cpp +++ b/segmenttree/test/beats_random_test.test.cpp @@ -1,14 +1,14 @@ #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" // DUMMY #include "../../random/xorshift.hpp" -#include "../acl_beats.hpp" +#include "../trees/range-chmin-chmax-add-range-sum.hpp" #include #include #include #include -using RangeChMinMaxAddSum::S, RangeChMinMaxAddSum::F; +using RCCARS = RangeChminChmaxAddRangeSum; int main() { for (int trial = 0; trial < 1 << 20; ++trial) { @@ -17,16 +17,14 @@ int main() { const int maxA = rand_int() % 50 + 1; const int Q = rand_int() % 10 + 1; - std::vector A(N); + std::vector A(N); std::vector simulate(N); for (int i = 0; i < N; ++i) { simulate.at(i) = rand_int() % (maxA + 1); - A.at(i) = S(simulate.at(i), 1); + A.at(i) = RCCARS::Gen(simulate.at(i)); } - segtree_beats - segtree(A); + RCCARS::segtree segtree(A); for (int q = 0; q < Q; ++q) { int tp = rand_int() % 4; @@ -43,17 +41,17 @@ int main() { int b = rand_int() % (maxA + 1); if (tp == 0) { for (int i = l; i < r; ++i) simulate.at(i) = std::min(simulate.at(i), b); - segtree.apply(l, r, RangeChMinMaxAddSum::F::chmin(b)); + segtree.apply(l, r, RCCARS::Chmin(b)); } if (tp == 1) { for (int i = l; i < r; ++i) simulate.at(i) = std::max(simulate.at(i), b); - segtree.apply(l, r, RangeChMinMaxAddSum::F::chmax(b)); + segtree.apply(l, r, RCCARS::Chmax(b)); } if (tp == 2) { for (int i = l; i < r; ++i) simulate.at(i) += b; - segtree.apply(l, r, RangeChMinMaxAddSum::F::add(b)); + segtree.apply(l, r, RCCARS::Add(b)); } } @@ -72,7 +70,7 @@ int main() { assert(prod.sum == std::accumulate(values.begin(), values.end(), 0LL)); - assert(prod.sz == r - l); + assert((int)prod.sz == r - l); assert(!prod.fail); if (values.front() != values.back()) { diff --git a/segmenttree/trees/range-chmin-chmax-add-range-sum.hpp b/segmenttree/trees/range-chmin-chmax-add-range-sum.hpp new file mode 100644 index 00000000..c3bbdee4 --- /dev/null +++ b/segmenttree/trees/range-chmin-chmax-add-range-sum.hpp @@ -0,0 +1,122 @@ +#pragma once +#include "../acl_beats.hpp" + +#include +#include +#include + +template struct RangeChminChmaxAddRangeSum { + static_assert(std::is_signed::value, "Num must be signed"); + + struct S { + Num lo, hi, lo2, hi2, sum; + unsigned sz, nlo, nhi; + bool fail; + S() : lo(INF), hi(-INF), lo2(INF), hi2(-INF), sum(0), sz(0), nlo(0), nhi(0), fail(0) {} + S(Num x, unsigned sz_) + : lo(x), hi(x), lo2(INF), hi2(-INF), sum(x * sz_), sz(sz_), nlo(sz_), nhi(sz_), + fail(0) {} + + template friend OStream &operator<<(OStream &os, const S s) { + return os << "[(" << s.lo << "x" << s.nlo << ", " << s.lo2 << ", " << s.hi2 << ", " + << s.hi << "x" << s.nhi << "), sz=" << s.sz << ", sum=" << s.sum << "]"; + } + }; + +private: + static Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { + assert(a <= a2); // a < a2 or a == a2 == INF + assert(c <= c2); // c < c2 or c == c2 == -INF + return a == c ? std::min(a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max(a, c); + } + + static Num second_highest(Num a, Num a2, Num b, Num b2) noexcept { + assert(a >= a2); // a > a2 or a == a2 == -INF + assert(b >= b2); // b > b2 or b == b2 == INF + return a == b ? std::max(a2, b2) : a2 >= b ? a2 : b2 >= a ? b2 : std::min(a, b); + } + + static S e() { return S(); } + + static S op(S l, S r) { + if (l.lo > l.hi) return r; + if (r.lo > r.hi) return l; + S ret; + ret.lo = std::min(l.lo, r.lo); + ret.hi = std::max(l.hi, r.hi); + ret.lo2 = second_lowest(l.lo, l.lo2, r.lo, r.lo2), + ret.hi2 = second_highest(l.hi, l.hi2, r.hi, r.hi2); + ret.sum = l.sum + r.sum; + ret.sz = l.sz + r.sz; + ret.nlo = l.nlo * (l.lo <= r.lo) + r.nlo * (r.lo <= l.lo); + ret.nhi = l.nhi * (l.hi >= r.hi) + r.nhi * (r.hi >= l.hi); + return ret; + } + + struct F { + Num lb, ub, bias; + F() : lb(-INF), ub(INF), bias(0) {} + F(Num chmax_, Num chmin_, Num add) : lb(chmax_), ub(chmin_), bias(add) {} + }; + + static F composition(F fnew, F fold) { + F ret; + ret.lb = std::max(std::min(fold.lb + fold.bias, fnew.ub), fnew.lb) - fold.bias; + ret.ub = std::min(std::max(fold.ub + fold.bias, fnew.lb), fnew.ub) - fold.bias; + ret.bias = fold.bias + fnew.bias; + return ret; + } + + static F id() { return F(); } + + static S mapping(F f, S x) { + if (x.sz == 0) return e(); + + // f の作用後 x の要素が 1 種類だけになるケース + if (x.lo == x.hi or f.lb == f.ub or f.lb >= x.hi or f.ub <= x.lo) { + return S(std::min(std::max(x.lo, f.lb), f.ub) + f.bias, x.sz); + } + + // 2 種類 -> 1 種類 + if (x.lo2 == x.hi) { + x.lo = x.hi2 = std::max(x.lo, f.lb) + f.bias; + x.hi = x.lo2 = std::min(x.hi, f.ub) + f.bias; + x.sum = x.lo * x.nlo + x.hi * x.nhi; + return x; + } + + // lo と lo2, hi と hi2 が潰れないケース + if (f.lb < x.lo2 and f.ub > x.hi2) { + Num nxt_lo = std::max(x.lo, f.lb), nxt_hi = std::min(x.hi, f.ub); + x.sum += (nxt_lo - x.lo) * x.nlo - (x.hi - nxt_hi) * x.nhi + f.bias * x.sz; + x.lo = nxt_lo + f.bias, x.hi = nxt_hi + f.bias, x.lo2 += f.bias, x.hi2 += f.bias; + return x; + } + + x.fail = 1; + return x; + } + +public: + static F Chmin(Num x) noexcept { return F(-INF, x, Num(0)); } + static F Chmax(Num x) noexcept { return F(x, INF, Num(0)); } + static F Add(Num x) noexcept { return F(-INF, INF, x); }; + + static S Gen(Num x, unsigned sz = 1) noexcept { return S(x, sz); } + + using segtree = segtree_beats; +}; +/* Usage: +using RCCARS = RangeChminChmaxAddRangeSum; + +vector init; +for (long long a : A) init.push_back(RCCARS::Gen(a)); + +RCCARS::segtree segtree(init); + +segtree.apply(l, r, RCCARS::Chmin(b)); +segtree.apply(l, r, RCCARS::Chmax(b)); +segtree.apply(l, r, RCCARS::Add(b)); + +long long ret = segtree.prod(l, r).sum; +*/ From 49a5c004899a1719a0174a429da054507ba316c6 Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:03:13 +0900 Subject: [PATCH 2/2] refactor beats --- ...ange-chmax-add-range-sum.aoj0427.test.cpp} | 18 +++-- .../trees/acl_range-add-chmax-range-sum.hpp | 64 --------------- .../trees/range-chmax-add-range-sum.hpp | 79 +++++++++++++++++++ 3 files changed, 89 insertions(+), 72 deletions(-) rename segmenttree/test/{beats_range-add-chmax-range-sum.test.cpp => beats_range-chmax-add-range-sum.aoj0427.test.cpp} (53%) delete mode 100644 segmenttree/trees/acl_range-add-chmax-range-sum.hpp create mode 100644 segmenttree/trees/range-chmax-add-range-sum.hpp diff --git a/segmenttree/test/beats_range-add-chmax-range-sum.test.cpp b/segmenttree/test/beats_range-chmax-add-range-sum.aoj0427.test.cpp similarity index 53% rename from segmenttree/test/beats_range-add-chmax-range-sum.test.cpp rename to segmenttree/test/beats_range-chmax-add-range-sum.aoj0427.test.cpp index 9fb1a738..f45bc21d 100644 --- a/segmenttree/test/beats_range-add-chmax-range-sum.test.cpp +++ b/segmenttree/test/beats_range-chmax-add-range-sum.aoj0427.test.cpp @@ -1,17 +1,19 @@ -#include "../trees/acl_range-add-chmax-range-sum.hpp" +#include "../trees/range-chmax-add-range-sum.hpp" #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0427" #include using namespace std; +using RCARS = RangeChmaxAddRangeSum; + int main() { cin.tie(nullptr), ios::sync_with_stdio(false); int N, tmp; cin >> N; - vector A(N); - for (auto &a : A) cin >> tmp, a = tmp; + vector A(N); + for (auto &a : A) cin >> tmp, a = RCARS::Gen(tmp); - RangeAddChmaxRangeSum::segtree segtree(A); + RCARS::segtree segtree(A); int Q, q, l, r, d; cin >> Q; @@ -20,12 +22,12 @@ int main() { cin >> q >> l >> r >> d; l--; if (q == 1) { - segtree.apply(l, r, RangeAddChmaxRangeSum::F::add(d)); + segtree.apply(l, r, RCARS::Add(d)); } else { auto before = segtree.prod(l, r).sum; - auto f1 = RangeAddChmaxRangeSum::F::add(-d); - auto f2 = RangeAddChmaxRangeSum::F::chmax(0); - segtree.apply(l, r, RangeAddChmaxRangeSum::composition(f2, f1)); + auto f1 = RCARS::Add(-d); + auto f2 = RCARS::Chmax(0); + segtree.apply(l, r, RCARS::composition(f2, f1)); auto after = segtree.prod(l, r).sum; cout << before - after << '\n'; } diff --git a/segmenttree/trees/acl_range-add-chmax-range-sum.hpp b/segmenttree/trees/acl_range-add-chmax-range-sum.hpp deleted file mode 100644 index 6093e02b..00000000 --- a/segmenttree/trees/acl_range-add-chmax-range-sum.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include "../acl_beats.hpp" - -// CUT begin -// Verified: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0427 -namespace RangeAddChmaxRangeSum { -#include - -template -inline Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { // a < a2, c < c2 - return a == c ? std::min(a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max(a, c); -} -using Num = int; -constexpr Num INF = 1 << 30; - -struct S { - Num lo, lo2, sum; - unsigned sz, nlo; - bool fail; - S() : lo(INF), lo2(INF), sum(0), sz(0), nlo(0), fail(false) {} - S(Num x, unsigned sz_ = 1) - : lo(x), lo2(INF), sum(Num(x) * sz_), sz(sz_), nlo(sz_), fail(false) {} -}; - -S e() { return S(); } - -S op(S l, S r) { - S ret; - ret.lo = std::min(l.lo, r.lo); - ret.lo2 = second_lowest(l.lo, l.lo2, r.lo, r.lo2); - ret.sum = l.sum + r.sum, ret.sz = l.sz + r.sz; - ret.nlo = l.nlo * (l.lo <= r.lo) + r.nlo * (r.lo <= l.lo); - return ret; -} - -struct F { - Num lb, bias; - F() : lb(-INF), bias(0) {} - F(Num chmax_, Num add) : lb(chmax_), bias(add) {} - static F chmax(Num x) noexcept { return F(x, Num(0)); } - static F add(Num x) noexcept { return F(-INF, x); }; -}; - -F composition(F fnew, F fold) { - F ret; - ret.lb = std::max(fold.lb + fold.bias, fnew.lb) - fold.bias; - ret.bias = fold.bias + fnew.bias; - return ret; -} - -F id() { return F(); } -S mapping(F f, S x) { - if (x.sz == 0) return e(); - if (f.lb < x.lo2) { - Num nxt_lo = std::max(x.lo, f.lb); - x.sum += (nxt_lo - x.lo) * x.nlo + f.bias * x.sz; - x.lo = nxt_lo + f.bias, x.lo2 += f.bias; - return x; - } - x.fail = 1; - return x; -} -using segtree = segtree_beats; -} // namespace RangeAddChmaxRangeSum diff --git a/segmenttree/trees/range-chmax-add-range-sum.hpp b/segmenttree/trees/range-chmax-add-range-sum.hpp new file mode 100644 index 00000000..0fc259fe --- /dev/null +++ b/segmenttree/trees/range-chmax-add-range-sum.hpp @@ -0,0 +1,79 @@ +#pragma once +#include "../acl_beats.hpp" +#include +#include + +// Verified: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0427 +template struct RangeChmaxAddRangeSum { + static_assert(std::is_signed::value, "Num must be signed"); + + static Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { // a < a2, c < c2 + return a == c ? std::min(a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max(a, c); + } + + struct S { + Num lo, lo2, sum; + unsigned sz, nlo; + bool fail; + S() : lo(INF), lo2(INF), sum(0), sz(0), nlo(0), fail(false) {} + S(Num x, unsigned sz_ = 1) + : lo(x), lo2(INF), sum(Num(x) * sz_), sz(sz_), nlo(sz_), fail(false) {} + }; + +private: + static S e() { return S(); } + + static S op(S l, S r) { + S ret; + ret.lo = std::min(l.lo, r.lo); + ret.lo2 = second_lowest(l.lo, l.lo2, r.lo, r.lo2); + ret.sum = l.sum + r.sum, ret.sz = l.sz + r.sz; + ret.nlo = l.nlo * (l.lo <= r.lo) + r.nlo * (r.lo <= l.lo); + return ret; + } + + struct F { + Num lb, bias; + F() : lb(-INF), bias(0) {} + F(Num chmax_, Num add) : lb(chmax_), bias(add) {} + }; + + static F id() { return F(); } + + static S mapping(F f, S x) { + if (x.sz == 0) return e(); + if (f.lb < x.lo2) { + Num nxt_lo = std::max(x.lo, f.lb); + x.sum += (nxt_lo - x.lo) * x.nlo + f.bias * x.sz; + x.lo = nxt_lo + f.bias, x.lo2 += f.bias; + return x; + } + x.fail = 1; + return x; + } + +public: + static F composition(F fnew, F fold) { + F ret; + ret.lb = std::max(fold.lb + fold.bias, fnew.lb) - fold.bias; + ret.bias = fold.bias + fnew.bias; + return ret; + } + + static F Chmax(Num x) noexcept { return F(x, Num(0)); } + static F Add(Num x) noexcept { return F(-INF, x); }; + + static S Gen(Num x, unsigned sz = 1) { return S{x, sz}; } + + using segtree = segtree_beats; +}; +/* Usage: +using RCARS = RangeChmaxAddRangeSum; +vector init; +for (auto a : A) init.push_back(RCARS::Gen(a, 1)); +RCARS::segtree tree(init); + +tree.apply(l, r, RCARS::Chmax(x)); +tree.apply(l, r, RCARS::Add(x)); +auto p = tree.prod(l, r); +*/