library

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

View the Project on GitHub maspypy/library

:warning: ds/segtree/range_add_make_decreasing.hpp

Depends on

Code

#include "ds/segtree/dual_segtree.hpp"
#include "alg/monoid/add.hpp"
#include "ds/fastset.hpp"

// 区間加算 / ある範囲を prefix 側から単調(増加/減少)になるように修正
// 指定しなかった場合 0 埋めで初期化される
// https://atcoder.jp/contests/joisc2019/tasks/joisc2019_e
// https://atcoder.jp/contests/joisp2024/tasks/joisp2024_i
struct Range_Add_Make_Monotonic_Decreasing {
  // 代表点の集合を持つ. 代表点に対する値を双対セグ木で持つ.
  // A[i-1]>A[i] となっている i 全体も持つ.
  int n;
  FastSet S, INC;
  Dual_SegTree<Monoid_Add<ll>> seg;

  Range_Add_Make_Monotonic_Decreasing() {}
  Range_Add_Make_Monotonic_Decreasing(int n) { build(n); }
  template <typename F>
  Range_Add_Make_Monotonic_Decreasing(int n, F f) {
    build(n, f);
  }
  Range_Add_Make_Monotonic_Decreasing(const vi& v) { build(v); }

  void build(int m) {
    build(m, [](int i) -> ll { return 0; });
  }
  template <typename F>
  void build(int m, F f) {
    vi v(m);
    FOR(i, m) v[i] = f(i);
    build(v);
  }
  void build(const vi& v) {
    n = len(v);
    seg.build(n, [&](int i) -> ll { return v[i]; }), S.build(n), INC.build(n + 1);
    FOR(i, n) S.insert(i);
    FOR(i, 1, n) if (v[i - 1] < v[i]) INC.insert(i);
  }

  ll get(int i) { return seg.get(S.prev(i)); }
  vi get_all() {
    auto A = seg.get_all();
    int p = 0;
    FOR(i, n) {
      if (S[i]) p = i;
      A[i] = A[p];
    }
    return A;
  }
  void set(int i, ll x) {
    split(i), split(i + 1);
    seg.set(i, x);
    INC.insert(i), INC.insert(i + 1);
  }
  void range_add(int L, int R, ll x) {
    split(L), split(R);
    if (x > 0) INC.insert(L);
    if (x < 0) INC.insert(R);
    seg.apply(L, R, x);
  }
  void range_assign(int L, int R, ll x) {
    split(L), split(R);
    INC.insert(L), INC.insert(R);
    S.enumerate(L, R, [&](int i) -> void { S.erase(i); });
    S.insert(L);
    seg.set(L, x);
  }
  void make_increasing(int L, int R) {
    split(L), split(R);
    INC.enumerate(L + 1, R, [&](int i) -> void {
      ll mi = get(i - 1);
      while (i < R) {
        INC.erase(i);
        ll now = get(i);
        if (mi > now) break;
        S.erase(i);
        i = S.next(i);
      }
    });
  }

private:
  void split(int p) {
    if (p == 0 || p == n || S[p]) return;
    seg.set(p, get(p));
    S.insert(p);
  }
};
#line 1 "ds/segtree/range_add_make_decreasing.hpp"

#line 2 "ds/segtree/dual_segtree.hpp"

template <typename Monoid>
struct Dual_SegTree {
  using MA = Monoid;
  using A = typename MA::value_type;
  int n, log, size;
  vc<A> laz;

  Dual_SegTree() : Dual_SegTree(0) {}
  Dual_SegTree(int n) {
    build(n, [&](int i) -> A { return MA::unit(); });
  }
  template <typename F>
  Dual_SegTree(int n, F f) {
    build(n, f);
  }

  template <typename F>
  void build(int m, F f) {
    n = m;
    log = 1;
    while ((1 << log) < n) ++log;
    size = 1 << log;
    laz.assign(size << 1, MA::unit());
    FOR(i, n) laz[size + i] = f(i);
  }
  void build(int n) {
    build(n, [&](int i) -> A { return MA::unit(); });
  }

  A get(int p) {
    assert(0 <= p && p < n);
    p += size;
    for (int i = log; i >= 1; i--) push(p >> i);
    return laz[p];
  }

  vc<A> get_all() {
    FOR(i, size) push(i);
    return {laz.begin() + size, laz.begin() + size + n};
  }

  void set(int p, A x) {
    get(p);
    laz[p + size] = x;
  }

  void apply(int l, int r, const A& a) {
    assert(0 <= l && l <= r && r <= n);
    if (l == r) return;
    l += size, r += size;
    if (!MA::commute) {
      for (int i = log; i >= 1; i--) {
        if (((l >> i) << i) != l) push(l >> i);
        if (((r >> i) << i) != r) push((r - 1) >> i);
      }
    }
    while (l < r) {
      if (l & 1) all_apply(l++, a);
      if (r & 1) all_apply(--r, a);
      l >>= 1, r >>= 1;
    }
  }

private:
  void push(int k) {
    if (laz[k] == MA::unit()) return;
    all_apply(2 * k, laz[k]), all_apply(2 * k + 1, laz[k]);
    laz[k] = MA::unit();
  }
  void all_apply(int k, A a) { laz[k] = MA::op(laz[k], a); }
};
#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 2 "ds/fastset.hpp"

// 64-ary tree

// space: (N/63) * u64

struct FastSet {
  static constexpr u32 B = 64;
  int n, log;
  vvc<u64> seg;

  FastSet() {}
  FastSet(int n) { build(n); }

  int size() { return n; }

  template <typename F>
  FastSet(int n, F f) {
    build(n, f);
  }

  void build(int m) {
    seg.clear();
    n = m;
    do {
      seg.push_back(vc<u64>((m + B - 1) / B));
      m = (m + B - 1) / B;
    } while (m > 1);
    log = len(seg);
  }
  template <typename F>
  void build(int n, F f) {
    build(n);
    FOR(i, n) { seg[0][i / B] |= u64(f(i)) << (i % B); }
    FOR(h, log - 1) {
      FOR(i, len(seg[h])) {
        seg[h + 1][i / B] |= u64(bool(seg[h][i])) << (i % B);
      }
    }
  }

  bool operator[](int i) const { return seg[0][i / B] >> (i % B) & 1; }
  void insert(int i) {
    for (int h = 0; h < log; h++) {
      seg[h][i / B] |= u64(1) << (i % B), i /= B;
    }
  }
  void add(int i) { insert(i); }
  void erase(int i) {
    u64 x = 0;
    for (int h = 0; h < log; h++) {
      seg[h][i / B] &= ~(u64(1) << (i % B));
      seg[h][i / B] |= x << (i % B);
      x = bool(seg[h][i / B]);
      i /= B;
    }
  }
  void remove(int i) { erase(i); }

  // min[x,n) or n

  int next(int i) {
    assert(i <= n);
    chmax(i, 0);
    for (int h = 0; h < log; h++) {
      if (i / B == seg[h].size()) break;
      u64 d = seg[h][i / B] >> (i % B);
      if (!d) {
        i = i / B + 1;
        continue;
      }
      i += lowbit(d);
      for (int g = h - 1; g >= 0; g--) {
        i *= B;
        i += lowbit(seg[g][i / B]);
      }
      return i;
    }
    return n;
  }

  // max [0,x], or -1

  int prev(int i) {
    assert(i >= -1);
    if (i >= n) i = n - 1;
    for (int h = 0; h < log; h++) {
      if (i == -1) break;
      u64 d = seg[h][i / B] << (63 - i % B);
      if (!d) {
        i = i / B - 1;
        continue;
      }
      i -= __builtin_clzll(d);
      for (int g = h - 1; g >= 0; g--) {
        i *= B;
        i += topbit(seg[g][i / B]);
      }
      return i;
    }
    return -1;
  }

  bool any(int l, int r) { return next(l) < r; }

  // [l, r)

  template <typename F>
  void enumerate(int l, int r, F f) {
    for (int x = next(l); x < r; x = next(x + 1)) f(x);
  }

  string to_string() {
    string s(n, '?');
    for (int i = 0; i < n; ++i) s[i] = ((*this)[i] ? '1' : '0');
    return s;
  }
};
#line 5 "ds/segtree/range_add_make_decreasing.hpp"

// 区間加算 / ある範囲を prefix 側から単調(増加/減少)になるように修正
// 指定しなかった場合 0 埋めで初期化される
// https://atcoder.jp/contests/joisc2019/tasks/joisc2019_e
// https://atcoder.jp/contests/joisp2024/tasks/joisp2024_i
struct Range_Add_Make_Monotonic_Decreasing {
  // 代表点の集合を持つ. 代表点に対する値を双対セグ木で持つ.
  // A[i-1]>A[i] となっている i 全体も持つ.
  int n;
  FastSet S, INC;
  Dual_SegTree<Monoid_Add<ll>> seg;

  Range_Add_Make_Monotonic_Decreasing() {}
  Range_Add_Make_Monotonic_Decreasing(int n) { build(n); }
  template <typename F>
  Range_Add_Make_Monotonic_Decreasing(int n, F f) {
    build(n, f);
  }
  Range_Add_Make_Monotonic_Decreasing(const vi& v) { build(v); }

  void build(int m) {
    build(m, [](int i) -> ll { return 0; });
  }
  template <typename F>
  void build(int m, F f) {
    vi v(m);
    FOR(i, m) v[i] = f(i);
    build(v);
  }
  void build(const vi& v) {
    n = len(v);
    seg.build(n, [&](int i) -> ll { return v[i]; }), S.build(n), INC.build(n + 1);
    FOR(i, n) S.insert(i);
    FOR(i, 1, n) if (v[i - 1] < v[i]) INC.insert(i);
  }

  ll get(int i) { return seg.get(S.prev(i)); }
  vi get_all() {
    auto A = seg.get_all();
    int p = 0;
    FOR(i, n) {
      if (S[i]) p = i;
      A[i] = A[p];
    }
    return A;
  }
  void set(int i, ll x) {
    split(i), split(i + 1);
    seg.set(i, x);
    INC.insert(i), INC.insert(i + 1);
  }
  void range_add(int L, int R, ll x) {
    split(L), split(R);
    if (x > 0) INC.insert(L);
    if (x < 0) INC.insert(R);
    seg.apply(L, R, x);
  }
  void range_assign(int L, int R, ll x) {
    split(L), split(R);
    INC.insert(L), INC.insert(R);
    S.enumerate(L, R, [&](int i) -> void { S.erase(i); });
    S.insert(L);
    seg.set(L, x);
  }
  void make_increasing(int L, int R) {
    split(L), split(R);
    INC.enumerate(L + 1, R, [&](int i) -> void {
      ll mi = get(i - 1);
      while (i < R) {
        INC.erase(i);
        ll now = get(i);
        if (mi > now) break;
        S.erase(i);
        i = S.next(i);
      }
    });
  }

private:
  void split(int p) {
    if (p == 0 || p == n || S[p]) return;
    seg.set(p, get(p));
    S.insert(p);
  }
};
Back to top page