library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:heavy_check_mark: convex/slope_trick/slope_trick_1.hpp

Depends on

Verified with

Code

#include "ds/double_end_queue_const_add.hpp"
#include "alg/monoid/add.hpp"

struct Slope_Trick_1 {
  struct FUNC {
    // 定義域の両端は que に入れることにして que が空でない状態を保つ
    Double_End_Queue_Const_Add<Monoid_Add<ll>> que_l, que_r;
    i128 min_f = 0;
    int size() { return que_l.size() + que_r.size(); }
  };

  // O(|a|)
  FUNC segment_func(ll L, ll R, ll a, ll b) {
    FUNC f;
    if (a >= 0) {
      f.min_f = i128(a) * L + b;
      f.que_l.push(L);
      FOR(a) f.que_r.push(L);
      f.que_r.push(R);
    } else {
      f.min_f = i128(a) * R + b;
      f.que_r.push(R);
      FOR(-a) f.que_l.push(R);
      f.que_l.push(L);
    }
    return f;
  }

  pair<ll, ll> domain(FUNC &f) { return {f.que_l.min(), f.que_r.max()}; }

  // O(N)
  i128 eval(FUNC &f, ll x) {
    auto [x0, x1] = domain(f);
    assert(x0 <= x && x <= x1);
    i128 ans = f.min_f;
    f.que_l.enumerate_all([&](ll l) -> void { ans += max<ll>(l - x, 0); });
    f.que_r.enumerate_all([&](ll r) -> void { ans += max<ll>(x - r, 0); });
    return ans;
  }

  // もとの min_f と定義域が交わる場合だけ実装した
  FUNC restrict_domain(FUNC &f, ll L, ll R) {
    auto [x0, x1] = domain(f);
    chmax(L, x0), chmin(R, x1);
    while (!f.que_l.empty() && f.que_l.min() <= L) { f.que_l.pop_min(); }
    while (!f.que_r.empty() && f.que_r.max() >= R) { f.que_r.pop_max(); }
    f.que_l.push(L);
    f.que_r.push(R);
    return f;
  }

  // +(ax+b), O(|a|*log)
  FUNC add_linear(FUNC &f, ll a, ll b) {
    auto [x0, x1] = domain(f);
    f.min_f += b;
    while (a > 0) {
      f.min_f += f.que_l.pop_max();
      f.que_r.push(f.que_l.pop_max());
      if (f.que_l.empty()) f.que_l.push(x0);
      --a;
    }
    while (a < 0) {
      f.min_f -= f.que_r.pop_min();
      f.que_l.push(f.que_r.pop_min());
      if (f.que_r.empty()) f.que_r.push(x0);
      ++a;
    }
    return f;
  }

  // (a-x)+
  FUNC add_a_minus_x(FUNC &f, ll a) {
    auto [x0, x1] = domain(f);
    assert(x0 <= x1);
    if (a <= x0) return f;
    if (x1 <= a) return add_linear(f, -1, a);
    ll x = f.que_r.min();
    f.min_f += max<ll>(a - x, 0);
    if (a <= x) {
      f.que_l.push(a);
    } else {
      f.que_l.push(f.que_r.pop_min());
      f.que_r.push(a);
    }
    return f;
  }

  // (x-a)+
  FUNC add_x_minus_a(FUNC &f, ll a) {
    auto [x0, x1] = domain(f);
    assert(x0 <= x1);
    if (a <= x0) return add_linear(f, 1, -a);
    if (x1 <= a) return f;
    ll x = f.que_l.max();
    f.min_f += max<ll>(x - a, 0);
    if (a >= x) {
      f.que_r.push(a);
    } else {
      f.que_r.push(f.que_l.pop_max());
      f.que_l.push(a);
    }
    return f;
  }

  // (x-a)+
  FUNC add_abs(FUNC &f, ll a) {
    f = add_a_minus_x(f, a);
    f = add_x_minus_a(f, a);
    return f;
  }

  FUNC clear_inc(FUNC &f) {
    auto [x0, x1] = domain(f);
    f.que_r.clear();
    f.que_r.push(x1);
    return f;
  }

  FUNC add(FUNC &f, FUNC &g) {
    auto [a0, a1] = domain(f);
    auto [b0, b1] = domain(g);
    ll x0 = max(a0, b0);
    ll x1 = min(a1, b1);
    assert(x0 <= x1);
    restrict_domain(f, x0, x1), restrict_domain(g, x0, x1);
    if (len(f) < len(g)) swap(f, g);
    f.min_f += g.min_f;
    for (auto l: g.que_l.dat) {
      l += g.que_l.add;
      // (l-x)+
      if (l <= f.que_r.min()) {
        f.que_l.push(l);
      } else {
        f.que_l.push(f.que_r.pop_min());
        f.que_r.push(l);
      }
      ll x = f.que_r.min();
      f.min_f += max<ll>(0, l - x);
    }
    return f;
  }

  // FUNC sum_all(vc<FUNC> &funcs) {}

  // FUNC shift(FUNC &f, T add_x, T add_y) {
  //   ST.apply(f.root, add_x);
  //   f.x0 += add_x, f.x1 += add_x, f.y0 += add_y;
  //   return f;
  // }

  // h[z]=min(x+y==z)f(x)+g(y)
  // FUNC convolve(FUNC &f, FUNC &g) {
  //   if (f.x0 > f.x1 || g.x0 > g.x1) { return {nullptr, infty<T>, -infty<T>, 0, 0}; }
  //   if (len(f) < len(g)) swap(f, g);
  //   shift(f, g.x0, g.y0), shift(g, -g.x0, -g.y0);
  //   if (len(g) == 0) { return convolve_segment(f, 0, g.x1, g.a0, 0); }
  //   auto tmp = ST.get_all(g.root);
  //   ST.free_subtree(g.root);
  //   f = convolve_segment(f, 0, tmp[0].fi, g.a0, 0);
  //   T a = g.a0;
  //   FOR(i, len(tmp)) {
  //     T nx = (i + 1 < len(tmp) ? tmp[i + 1].fi : g.x1);
  //     a += tmp[i].se;
  //     f = convolve_segment(f, 0, nx - tmp[i].fi, a, 0);
  //     for (auto &[x, a]: ST.get_all(f.root)) {
  //       assert(f.x0 <= x && x <= f.x1);
  //       if (f.root) assert(!f.root->p);
  //     }
  //   }
  //   return f;
  // }

  // [x0,x1], y=ax+b
  // FUNC convolve_segment(FUNC &f, T x0, T x1, T a, T b) {
  //   assert(x0 <= x1);
  //   if (f.x0 > f.x1) { return {nullptr, infty<T>, -infty<T>, 0, 0}; }
  //   f = shift(f, x0, a * x0 + b);
  //   T d = x1 - x0;
  //   if (d == 0) return f;
  //   // (0,0) から (x1,ax1) への線分をどこかに挿入する
  //   // 特に x0, y0 はこのままでよい
  //   if (f.x0 == f.x1) { return {nullptr, f.x0, f.x0 + d, a, f.y0}; }
  //   // 先頭に挿入できる場合
  //   if (a <= f.a0) {
  //     ST.apply(f.root, d);
  //     f.root = ST.merge(ST.new_node({f.x0 + d, f.a0 - a}), f.root);
  //     f.x1 += d, f.a0 = a;
  //     return f;
  //   }
  //   // 末尾に挿入できる場合
  //   T a_last = f.a0 + ST.prod(f.root).fi;
  //   if (a_last <= a) {
  //     f.root = ST.merge(f.root, ST.new_node({f.x1, a - a_last}));
  //     f.x1 += d;
  //     return f;
  //   }
  //   // 間のどこかに挿入
  //   auto [l, r] = ST.split_max_right_prod(f.root, [&](auto prod) -> bool { return f.a0 + prod.fi < a; });
  //   T asum = ST.prod(l).fi;
  //   T a1 = a - (asum + f.a0);
  //   auto [xx, aa] = ST.get(r, 0);
  //   ST.apply(r, d);
  //   ST.set(r, 0, {xx + d, aa - a1});
  //   f.root = ST.merge3(l, ST.new_node({xx, a1}), r);
  //   f.x1 += d;
  //   return f;
  // }

  // fx,x
  tuple<i128, ll, ll> get_min(FUNC &f) { return {f.min_f, f.que_l.max(), f.que_r.min()}; }
};
#line 1 "convex/slope_trick/slope_trick_1.hpp"

#line 1 "ds/double_end_queue_const_add.hpp"
// 全体加算もできるようにしよう
// Monoid_Add<T> を渡す感じで. T は operator< が定義されている必要あり.
template <typename Monoid>
struct Double_End_Queue_Const_Add {
  using MX = Monoid;
  using T = typename MX::value_type;
  vector<T> dat;
  T add;

  Double_End_Queue_Const_Add() : add(MX::unit()) {}
  Double_End_Queue_Const_Add(vc<T>& A) : add(MX::unit()) { build(A); }

  int size() { return dat.size(); }
  bool empty() { return dat.empty(); }
  T min() { return MX::op(dat[0], add); }
  T max() { return MX::op(add, (len(dat) == 1 ? dat[0] : dat[1])); }

  void build(vc<T>& A) {
    add = MX::unit();
    dat = A;
    int n = len(dat);
    FOR_R(i, n) { down(i); }
  }
  void clear() {
    dat.clear(), dat.shrink_to_fit();
    add = 0;
  }

  void push(T x) { dat.eb(x - add), up(); }

  T pop_min() {
    assert(!dat.empty());
    swap(dat[0], dat.back());
    T res = POP(dat);
    down(0);
    return res + add;
  }

  T pop_max() {
    assert(!dat.empty());
    if (len(dat) <= 2) { return POP(dat) + add; }
    swap(dat[1], dat.back());
    T res = POP(dat);
    down(1);
    return res + add;
  }

  template <typename F>
  void enumerate_all(F f) {
    for (auto& x: dat) f(x + add);
  }

private:
  inline int parent(int i) { return (i - 4 + (i & 3)) / 2; }

  void down(int i) {
    int n = len(dat);
    if (i % 2 == 0) {
      while (1) {
        if (i + 1 < n && dat[i + 1] < dat[i]) swap(dat[i], dat[i + 1]);
        int j = i, l = 2 * i + 2, r = 2 * i + 4;
        if (l < n && dat[l] < dat[j]) j = l;
        if (r < n && dat[r] < dat[j]) j = r;
        if (i == j) break;
        swap(dat[i], dat[j]), i = j;
      }
    } else {
      while (1) {
        if (dat[i] < dat[i - 1]) swap(dat[i - 1], dat[i]);
        int j = i, l = 2 * i + 1, r = 2 * i + 3;
        if (r >= n) --r;
        if (l >= n) --l;
        if (l < n && dat[j] < dat[l]) j = l;
        if (r < n && dat[j] < dat[r]) j = r;
        if (i == j) break;
        swap(dat[i], dat[j]), i = j;
        if (i % 2 == 0) break;
      }
    }
  }

  void up() {
    int i = len(dat) - 1;
    if (2 <= i && i % 2 == 0) {
      int p = parent(i) ^ 1;
      if (dat[p] < dat[i]) { swap(dat[i], dat[p]), i = p; }
    }
    if (i % 2 == 1 && dat[i] < dat[i - 1]) { swap(dat[i - 1], dat[i]), --i; }
    if (i % 2 == 0) {
      while (i >= 2) {
        int p = parent(i);
        if (!(dat[i] < dat[p])) break;
        swap(dat[p], dat[i]), i = p;
      }
      return;
    }
    while (i >= 3) {
      int p = parent(i);
      if (!(dat[p] < dat[i])) break;
      swap(dat[p], dat[i]), i = p;
    }
  }
};
#line 2 "alg/monoid/add.hpp"

template <typename E>
struct Monoid_Add {
  using X = E;
  using value_type = X;
  static constexpr X op(const X &x, const X &y) noexcept { return x + y; }
  static constexpr X inverse(const X &x) noexcept { return -x; }
  static constexpr X power(const X &x, ll n) noexcept { return X(n) * x; }
  static constexpr X unit() { return X(0); }
  static constexpr bool commute = true;
};
#line 4 "convex/slope_trick/slope_trick_1.hpp"

struct Slope_Trick_1 {
  struct FUNC {
    // 定義域の両端は que に入れることにして que が空でない状態を保つ
    Double_End_Queue_Const_Add<Monoid_Add<ll>> que_l, que_r;
    i128 min_f = 0;
    int size() { return que_l.size() + que_r.size(); }
  };

  // O(|a|)
  FUNC segment_func(ll L, ll R, ll a, ll b) {
    FUNC f;
    if (a >= 0) {
      f.min_f = i128(a) * L + b;
      f.que_l.push(L);
      FOR(a) f.que_r.push(L);
      f.que_r.push(R);
    } else {
      f.min_f = i128(a) * R + b;
      f.que_r.push(R);
      FOR(-a) f.que_l.push(R);
      f.que_l.push(L);
    }
    return f;
  }

  pair<ll, ll> domain(FUNC &f) { return {f.que_l.min(), f.que_r.max()}; }

  // O(N)
  i128 eval(FUNC &f, ll x) {
    auto [x0, x1] = domain(f);
    assert(x0 <= x && x <= x1);
    i128 ans = f.min_f;
    f.que_l.enumerate_all([&](ll l) -> void { ans += max<ll>(l - x, 0); });
    f.que_r.enumerate_all([&](ll r) -> void { ans += max<ll>(x - r, 0); });
    return ans;
  }

  // もとの min_f と定義域が交わる場合だけ実装した
  FUNC restrict_domain(FUNC &f, ll L, ll R) {
    auto [x0, x1] = domain(f);
    chmax(L, x0), chmin(R, x1);
    while (!f.que_l.empty() && f.que_l.min() <= L) { f.que_l.pop_min(); }
    while (!f.que_r.empty() && f.que_r.max() >= R) { f.que_r.pop_max(); }
    f.que_l.push(L);
    f.que_r.push(R);
    return f;
  }

  // +(ax+b), O(|a|*log)
  FUNC add_linear(FUNC &f, ll a, ll b) {
    auto [x0, x1] = domain(f);
    f.min_f += b;
    while (a > 0) {
      f.min_f += f.que_l.pop_max();
      f.que_r.push(f.que_l.pop_max());
      if (f.que_l.empty()) f.que_l.push(x0);
      --a;
    }
    while (a < 0) {
      f.min_f -= f.que_r.pop_min();
      f.que_l.push(f.que_r.pop_min());
      if (f.que_r.empty()) f.que_r.push(x0);
      ++a;
    }
    return f;
  }

  // (a-x)+
  FUNC add_a_minus_x(FUNC &f, ll a) {
    auto [x0, x1] = domain(f);
    assert(x0 <= x1);
    if (a <= x0) return f;
    if (x1 <= a) return add_linear(f, -1, a);
    ll x = f.que_r.min();
    f.min_f += max<ll>(a - x, 0);
    if (a <= x) {
      f.que_l.push(a);
    } else {
      f.que_l.push(f.que_r.pop_min());
      f.que_r.push(a);
    }
    return f;
  }

  // (x-a)+
  FUNC add_x_minus_a(FUNC &f, ll a) {
    auto [x0, x1] = domain(f);
    assert(x0 <= x1);
    if (a <= x0) return add_linear(f, 1, -a);
    if (x1 <= a) return f;
    ll x = f.que_l.max();
    f.min_f += max<ll>(x - a, 0);
    if (a >= x) {
      f.que_r.push(a);
    } else {
      f.que_r.push(f.que_l.pop_max());
      f.que_l.push(a);
    }
    return f;
  }

  // (x-a)+
  FUNC add_abs(FUNC &f, ll a) {
    f = add_a_minus_x(f, a);
    f = add_x_minus_a(f, a);
    return f;
  }

  FUNC clear_inc(FUNC &f) {
    auto [x0, x1] = domain(f);
    f.que_r.clear();
    f.que_r.push(x1);
    return f;
  }

  FUNC add(FUNC &f, FUNC &g) {
    auto [a0, a1] = domain(f);
    auto [b0, b1] = domain(g);
    ll x0 = max(a0, b0);
    ll x1 = min(a1, b1);
    assert(x0 <= x1);
    restrict_domain(f, x0, x1), restrict_domain(g, x0, x1);
    if (len(f) < len(g)) swap(f, g);
    f.min_f += g.min_f;
    for (auto l: g.que_l.dat) {
      l += g.que_l.add;
      // (l-x)+
      if (l <= f.que_r.min()) {
        f.que_l.push(l);
      } else {
        f.que_l.push(f.que_r.pop_min());
        f.que_r.push(l);
      }
      ll x = f.que_r.min();
      f.min_f += max<ll>(0, l - x);
    }
    return f;
  }

  // FUNC sum_all(vc<FUNC> &funcs) {}

  // FUNC shift(FUNC &f, T add_x, T add_y) {
  //   ST.apply(f.root, add_x);
  //   f.x0 += add_x, f.x1 += add_x, f.y0 += add_y;
  //   return f;
  // }

  // h[z]=min(x+y==z)f(x)+g(y)
  // FUNC convolve(FUNC &f, FUNC &g) {
  //   if (f.x0 > f.x1 || g.x0 > g.x1) { return {nullptr, infty<T>, -infty<T>, 0, 0}; }
  //   if (len(f) < len(g)) swap(f, g);
  //   shift(f, g.x0, g.y0), shift(g, -g.x0, -g.y0);
  //   if (len(g) == 0) { return convolve_segment(f, 0, g.x1, g.a0, 0); }
  //   auto tmp = ST.get_all(g.root);
  //   ST.free_subtree(g.root);
  //   f = convolve_segment(f, 0, tmp[0].fi, g.a0, 0);
  //   T a = g.a0;
  //   FOR(i, len(tmp)) {
  //     T nx = (i + 1 < len(tmp) ? tmp[i + 1].fi : g.x1);
  //     a += tmp[i].se;
  //     f = convolve_segment(f, 0, nx - tmp[i].fi, a, 0);
  //     for (auto &[x, a]: ST.get_all(f.root)) {
  //       assert(f.x0 <= x && x <= f.x1);
  //       if (f.root) assert(!f.root->p);
  //     }
  //   }
  //   return f;
  // }

  // [x0,x1], y=ax+b
  // FUNC convolve_segment(FUNC &f, T x0, T x1, T a, T b) {
  //   assert(x0 <= x1);
  //   if (f.x0 > f.x1) { return {nullptr, infty<T>, -infty<T>, 0, 0}; }
  //   f = shift(f, x0, a * x0 + b);
  //   T d = x1 - x0;
  //   if (d == 0) return f;
  //   // (0,0) から (x1,ax1) への線分をどこかに挿入する
  //   // 特に x0, y0 はこのままでよい
  //   if (f.x0 == f.x1) { return {nullptr, f.x0, f.x0 + d, a, f.y0}; }
  //   // 先頭に挿入できる場合
  //   if (a <= f.a0) {
  //     ST.apply(f.root, d);
  //     f.root = ST.merge(ST.new_node({f.x0 + d, f.a0 - a}), f.root);
  //     f.x1 += d, f.a0 = a;
  //     return f;
  //   }
  //   // 末尾に挿入できる場合
  //   T a_last = f.a0 + ST.prod(f.root).fi;
  //   if (a_last <= a) {
  //     f.root = ST.merge(f.root, ST.new_node({f.x1, a - a_last}));
  //     f.x1 += d;
  //     return f;
  //   }
  //   // 間のどこかに挿入
  //   auto [l, r] = ST.split_max_right_prod(f.root, [&](auto prod) -> bool { return f.a0 + prod.fi < a; });
  //   T asum = ST.prod(l).fi;
  //   T a1 = a - (asum + f.a0);
  //   auto [xx, aa] = ST.get(r, 0);
  //   ST.apply(r, d);
  //   ST.set(r, 0, {xx + d, aa - a1});
  //   f.root = ST.merge3(l, ST.new_node({xx, a1}), r);
  //   f.x1 += d;
  //   return f;
  // }

  // fx,x
  tuple<i128, ll, ll> get_min(FUNC &f) { return {f.min_f, f.que_l.max(), f.que_r.min()}; }
};
Back to top page