|
| 1 | +#pragma once |
| 2 | + |
| 3 | +template <class T> |
| 4 | +struct SlopeTrick { |
| 5 | + const T INF = numeric_limits<T>::max() / 3; |
| 6 | + T min_f; |
| 7 | + priority_queue<T, vector<T>, less<> > pq_l; |
| 8 | + priority_queue<T, vector<T>, greater<> > pq_r; |
| 9 | + T add_l, add_r; |
| 10 | + SlopeTrick() : min_f(0), add_l(0), add_r(0) {} |
| 11 | + T get_min() const { return min_f; } |
| 12 | + pair<T, T> get_min_range() const { return {top_l(), top_r()}; } |
| 13 | + // f(x) += a |
| 14 | + void add_const(const T& a) { min_f += a; } |
| 15 | + // f(x) += max(0, x - a) |
| 16 | + void add_x_minus_a(const T& a) { |
| 17 | + min_f += max(T(0), top_l() - a); |
| 18 | + push_l(a); |
| 19 | + push_r(pop_l()); |
| 20 | + } |
| 21 | + // f(x) += max(a - x, 0) |
| 22 | + void add_a_minus_x(const T& a) { |
| 23 | + min_f += max(T(0), a - top_r()); |
| 24 | + push_r(a); |
| 25 | + push_l(pop_r()); |
| 26 | + } |
| 27 | + // f(x) += abs(x - a) |
| 28 | + void add_abs(const T& a) { |
| 29 | + add_a_minus_x(a); |
| 30 | + add_x_minus_a(a); |
| 31 | + } |
| 32 | + // f(x) <- min_{y <= x} f(y) |
| 33 | + // \/ -> \_ |
| 34 | + void clear_right() { |
| 35 | + while (!pq_r.empty()) pq_r.pop(); |
| 36 | + } |
| 37 | + // f(x) <- min_{x <= y} f(y) |
| 38 | + // \/ -> _/ |
| 39 | + void clear_left() { |
| 40 | + while (!pq_l.empty()) pq_l.pop(); |
| 41 | + } |
| 42 | + // f(x) <- min_{x-b <= y <= x-a} f(y) |
| 43 | + // \/ -> \_/ |
| 44 | + void shift(const T& a, const T& b) { |
| 45 | + assert(a <= b); |
| 46 | + add_l += a; |
| 47 | + add_r += b; |
| 48 | + } |
| 49 | + |
| 50 | + T get_destructive(const T& x) { |
| 51 | + T ret = min_f; |
| 52 | + while (!pq_l.empty()) ret += max(T(0), pop_l() - x); |
| 53 | + while (!pq_r.empty()) ret += max(T(0), x - pop_r()); |
| 54 | + return ret; |
| 55 | + } |
| 56 | + void merge(SlopeTrick& st) { |
| 57 | + if (st.size() > size()) { |
| 58 | + swap(st.pq_l, pq_l); |
| 59 | + swap(st.pq_r, pq_r); |
| 60 | + swap(st.add_l, add_l); |
| 61 | + swap(st.add_r, add_r); |
| 62 | + swap(st.min_f, min_f); |
| 63 | + } |
| 64 | + while (!st.pq_r.empty()) add_x_minus_a(st.pop_r()); |
| 65 | + while (!st.pq_l.empty()) add_a_minus_x(st.pop_l()); |
| 66 | + min_f += st.min_f; |
| 67 | + } |
| 68 | + |
| 69 | + private: |
| 70 | + void push_r(const T& a) { pq_r.push(a - add_r); } |
| 71 | + T top_r() const { return pq_r.empty() ? INF : pq_r.top() + add_r; } |
| 72 | + T pop_r() { |
| 73 | + T val = top_r(); |
| 74 | + if (!pq_r.empty()) pq_r.pop(); |
| 75 | + return val; |
| 76 | + } |
| 77 | + void push_l(const T& a) { pq_l.push(a - add_l); } |
| 78 | + T top_l() const { return pq_l.empty() ? -INF : pq_l.top() + add_l; } |
| 79 | + T pop_l() { |
| 80 | + T val = top_l(); |
| 81 | + if (!pq_l.empty()) pq_l.pop(); |
| 82 | + return val; |
| 83 | + } |
| 84 | + size_t size() { return pq_l.size() + pq_r.size(); } |
| 85 | +}; |
| 86 | + |
| 87 | +/** |
| 88 | + * @brief Slope Trick |
| 89 | + * @docs docs/data-structure/slope-trick.md |
| 90 | + */ |
0 commit comments