11#pragma once
22#include " acl_lazysegtree.hpp"
33
4- // CUT begin
54template <class S , S (*op)(S, S), S (*e)(), class F , S (*mapping)(F, S), F (*composition)(F, F),
65 F (*id)()>
76class segtree_beats : public atcoder::lazy_segtree<S, op, e, F, mapping, composition, id> {
@@ -19,12 +18,14 @@ class segtree_beats : public atcoder::lazy_segtree<S, op, e, F, mapping, composi
1918namespace RangeChMinMaxAddSum {
2019#include < algorithm>
2120
22- template <typename Num>
23- inline Num second_lowest (Num a, Num a2, Num c, Num c2) noexcept { // a < a2, c < c2
21+ template <typename Num> inline Num second_lowest (Num a, Num a2, Num c, Num c2) noexcept {
22+ assert (a <= a2); // a < a2 or a == a2 == INF
23+ assert (c <= c2); // c < c2 or c == c2 == -INF
2424 return a == c ? std::min (a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max (a, c);
2525}
26- template <typename Num>
27- inline Num second_highest (Num a, Num a2, Num b, Num b2) noexcept { // a > a2, b > b2
26+ template <typename Num> inline Num second_highest (Num a, Num a2, Num b, Num b2) noexcept {
27+ assert (a >= a2); // a > a2 or a == a2 == -INF
28+ assert (b >= b2); // b > b2 or b == b2 == INF
2829 return a == b ? std::max (a2, b2) : a2 >= b ? a2 : b2 >= a ? b2 : std::min (a, b);
2930}
3031
@@ -36,7 +37,7 @@ struct S {
3637 unsigned sz, nlo, nhi;
3738 bool fail;
3839 S () : lo(BINF), hi(-BINF), lo2(BINF), hi2(-BINF), sum(0 ), sz(0 ), nlo(0 ), nhi(0 ), fail(0 ) {}
39- S (BNum x, unsigned sz_ = 1 )
40+ S (BNum x, unsigned sz_)
4041 : lo(x), hi(x), lo2(BINF), hi2(-BINF), sum(x * sz_), sz(sz_), nlo(sz_), nhi(sz_), fail(0 ) {}
4142 friend std::ostream &operator <<(std::ostream &os, const S s) {
4243 return os << " [(" << s.lo << " x" << s.nlo << " , " << s.lo2 << " , " << s.hi2 << " , " << s.hi
@@ -49,10 +50,12 @@ S op(S l, S r) {
4950 if (l.lo > l.hi ) return r;
5051 if (r.lo > r.hi ) return l;
5152 S ret;
52- ret.lo = std::min (l.lo , r.lo ), ret.hi = std::max (l.hi , r.hi );
53+ ret.lo = std::min (l.lo , r.lo );
54+ ret.hi = std::max (l.hi , r.hi );
5355 ret.lo2 = second_lowest (l.lo , l.lo2 , r.lo , r.lo2 ),
5456 ret.hi2 = second_highest (l.hi , l.hi2 , r.hi , r.hi2 );
55- ret.sum = l.sum + r.sum , ret.sz = l.sz + r.sz ;
57+ ret.sum = l.sum + r.sum ;
58+ ret.sz = l.sz + r.sz ;
5659 ret.nlo = l.nlo * (l.lo <= r.lo ) + r.nlo * (r.lo <= l.lo );
5760 ret.nhi = l.nhi * (l.hi >= r.hi ) + r.nhi * (r.hi >= l.hi );
5861 return ret;
@@ -76,21 +79,32 @@ F composition(F fnew, F fold) {
7679F id () { return F (); }
7780S mapping (F f, S x) {
7881 if (x.sz == 0 ) return e ();
79- if (x.lo == x.hi or f.lb == f.ub or f.lb >= x.hi or f.ub < x.lo )
82+
83+ // f の作用後 x の要素が 1 種類だけになるケース
84+ if (x.lo == x.hi or f.lb == f.ub or f.lb >= x.hi or f.ub <= x.lo ) {
8085 return S (std::min (std::max (x.lo , f.lb ), f.ub ) + f.bias , x.sz );
86+ }
87+
88+ // 2 種類 -> 1 種類
8189 if (x.lo2 == x.hi ) {
82- x.lo = x.hi2 = std::max (x.lo , f.lb ) + f.bias , x.hi = x.lo2 = std::min (x.hi , f.ub ) + f.bias ;
90+ x.lo = x.hi2 = std::max (x.lo , f.lb ) + f.bias ;
91+ x.hi = x.lo2 = std::min (x.hi , f.ub ) + f.bias ;
8392 x.sum = x.lo * x.nlo + x.hi * x.nhi ;
8493 return x;
8594 }
95+
96+ // lo と lo2, hi と hi2 が潰れないケース
8697 if (f.lb < x.lo2 and f.ub > x.hi2 ) {
8798 BNum nxt_lo = std::max (x.lo , f.lb ), nxt_hi = std::min (x.hi , f.ub );
8899 x.sum += (nxt_lo - x.lo ) * x.nlo - (x.hi - nxt_hi) * x.nhi + f.bias * x.sz ;
89100 x.lo = nxt_lo + f.bias , x.hi = nxt_hi + f.bias , x.lo2 += f.bias , x.hi2 += f.bias ;
90101 return x;
91102 }
103+
92104 x.fail = 1 ;
93105 return x;
94106}
107+
95108using segtree = segtree_beats<S, op, e, F, mapping, composition, id>;
109+
96110} // namespace RangeChMinMaxAddSum
0 commit comments