Skip to the content.

:x: library/datastructure/SlopeTrick.hpp

Depends on

Verified with

Code

// reference:https://maspypy.com/slope-trick-1-解説編
template <typename T> class SlopeTrick {
    static constexpr T MIN = std::numeric_limits<T>::lowest() / 2;
    static constexpr T MAX = std::numeric_limits<T>::max() / 2;
    std::priority_queue<T> L;
    std::priority_queue<T, std::vector<T>, std::greater<T>> R;
    T add_l, add_r;

    T L0() const { return L.size() ? L.top() + add_l : MIN; }
    T R0() const { return R.size() ? R.top() + add_r : MAX; }
    void push_L(T a) { L.push(a - add_l); }
    void push_R(T a) { R.push(a - add_r); }

  public:
    T min_f;
    SlopeTrick() : add_l(0), add_r(0), min_f(0) {}

    int size() const { return L.size() + R.size(); }

    std::tuple<T, T, T> get_min_range() const { return {L0(), R0(), min_f}; }

    void operator+=(const T &a) { min_f += a; }

    // (x-a)+
    void add_x_minus_a(T a) {
        if (a < L0()) {
            min_f += L0() - a;
            push_R(L0());
            L.pop();
            push_L(a);
        } else
            push_R(a);
    }

    // (a-x)+
    void add_a_minus_x(T a) {
        if (a > R0()) {
            min_f += a - R0();
            push_L(R0());
            R.pop();
            push_R(a);
        } else
            push_L(a);
    }

    // |x-a|
    void add_abs(T a) {
        add_x_minus_a(a);
        add_a_minus_x(a);
    }

    // 増加側を消して、減少側のみにする
    void clear_inc() { R = {}; }
    // 減少側を消して、増加側のみにする
    void clear_dec() { L = {}; }

    // g(x) = min_{x-b <= y <= x-a} f(y)
    void sliding_window_minimum(const T &a, const T &b) {
        add_l += a;
        add_r += b;
    }

    void shift(const T &a) { sliding_window_minimum(a, a); }

    // O(nlogn) n=size
    T operator()(T x) const {
        T y = min_f;
        if (x < L0()) {
            auto L_cpy = L;
            while (L_cpy.size()) {
                T a = L_cpy.top() + add_l;
                L_cpy.pop();
                if (a <= x)
                    break;
                y += a - x;
            }
        }
        if (x > R0()) {
            auto R_cpy = R;
            while (R_cpy.size()) {
                T a = R_cpy.top() + add_r;
                R_cpy.pop();
                if (x <= a)
                    break;
                y += x - a;
            }
        }
        return y;
    }

    // O(mlog(n+m)) n=size,m=g.size()
    SlopeTrick &operator+=(SlopeTrick g) {
        min_f += g.min_f;
        while (g.L.size()) {
            T a = g.L0();
            g.L.pop();
            add_a_minus_x(a);
        }
        while (g.R.size()) {
            T a = g.R0();
            g.R.pop();
            add_x_minus_a(a);
        }
        return *this;
    }

    SlopeTrick operator+(SlopeTrick g) const {
        if (size() < g.size())
            return g += *this;
        return (*this) += g;
    }
};
#line 1 "library/datastructure/SlopeTrick.hpp"
// reference:https://maspypy.com/slope-trick-1-解説編
template <typename T> class SlopeTrick {
    static constexpr T MIN = std::numeric_limits<T>::lowest() / 2;
    static constexpr T MAX = std::numeric_limits<T>::max() / 2;
    std::priority_queue<T> L;
    std::priority_queue<T, std::vector<T>, std::greater<T>> R;
    T add_l, add_r;

    T L0() const { return L.size() ? L.top() + add_l : MIN; }
    T R0() const { return R.size() ? R.top() + add_r : MAX; }
    void push_L(T a) { L.push(a - add_l); }
    void push_R(T a) { R.push(a - add_r); }

  public:
    T min_f;
    SlopeTrick() : add_l(0), add_r(0), min_f(0) {}

    int size() const { return L.size() + R.size(); }

    std::tuple<T, T, T> get_min_range() const { return {L0(), R0(), min_f}; }

    void operator+=(const T &a) { min_f += a; }

    // (x-a)+
    void add_x_minus_a(T a) {
        if (a < L0()) {
            min_f += L0() - a;
            push_R(L0());
            L.pop();
            push_L(a);
        } else
            push_R(a);
    }

    // (a-x)+
    void add_a_minus_x(T a) {
        if (a > R0()) {
            min_f += a - R0();
            push_L(R0());
            R.pop();
            push_R(a);
        } else
            push_L(a);
    }

    // |x-a|
    void add_abs(T a) {
        add_x_minus_a(a);
        add_a_minus_x(a);
    }

    // 増加側を消して、減少側のみにする
    void clear_inc() { R = {}; }
    // 減少側を消して、増加側のみにする
    void clear_dec() { L = {}; }

    // g(x) = min_{x-b <= y <= x-a} f(y)
    void sliding_window_minimum(const T &a, const T &b) {
        add_l += a;
        add_r += b;
    }

    void shift(const T &a) { sliding_window_minimum(a, a); }

    // O(nlogn) n=size
    T operator()(T x) const {
        T y = min_f;
        if (x < L0()) {
            auto L_cpy = L;
            while (L_cpy.size()) {
                T a = L_cpy.top() + add_l;
                L_cpy.pop();
                if (a <= x)
                    break;
                y += a - x;
            }
        }
        if (x > R0()) {
            auto R_cpy = R;
            while (R_cpy.size()) {
                T a = R_cpy.top() + add_r;
                R_cpy.pop();
                if (x <= a)
                    break;
                y += x - a;
            }
        }
        return y;
    }

    // O(mlog(n+m)) n=size,m=g.size()
    SlopeTrick &operator+=(SlopeTrick g) {
        min_f += g.min_f;
        while (g.L.size()) {
            T a = g.L0();
            g.L.pop();
            add_a_minus_x(a);
        }
        while (g.R.size()) {
            T a = g.R0();
            g.R.pop();
            add_x_minus_a(a);
        }
        return *this;
    }

    SlopeTrick operator+(SlopeTrick g) const {
        if (size() < g.size())
            return g += *this;
        return (*this) += g;
    }
};
Back to top page