Skip to the content.

:heavy_check_mark: Range Set Range Prod
(segment-tree/range-set-range-prod.hpp)

モノイド $(T,\cdot,e)$ の列に対する区間代入と区間積を扱う.

RangeSetRangeProd<M> として使う. Mvalue_type, op(x,y), e() を持つモノイドを表す型.

長さ $N$ の列 $A=(A_0,A_1,\dots,A_{N-1})$ に対し,空間計算量 $O(N)$ のもとで以下の操作を行える.

二分探索では cond(e) が真であり,判定が単調であることを要求する.

アルゴリズム

$x$ を代入するクエリごとに

\[x,\ x^2,\ x^4,\ \dots,\ x^{2^{\lceil\log N\rceil}}\]

を計算する.セグメント木の各節点が表す区間の長さは二冪なので,区間全体を $x$ に置き換えたときの積を $O(1)$ 回の参照で得られる.

$O(N/\log N)$ 回の区間代入ごとに全ての遅延値を子へ伝播し,保存した冪を破棄する.この伝播は $O(N)$ 時間なので,区間代入は償却 $O(\log N)$ 時間となる.全伝播が発生する単一の区間代入は最悪 $O(N)$ 時間かかる.

資料

Depends on

Verified with

Code

#pragma once
#include "algebraic-structure/monoid.hpp"

template <class M>
REQUIRES(Monoid<M>)
struct RangeSetRangeProd {
  using T = typename M::value_type;

 private:
  int _n, size, log, history_limit;
  vector<T> d;
  vector<int> lz, height;
  vector<vector<T>> history;

  void update(int k) { d[k] = M::op(d[2 * k], d[2 * k + 1]); }
  void all_apply(int k, int id) {
    d[k] = history[id][height[k]];
    if (k < size) lz[k] = id;
  }
  void push(int k) {
    if (lz[k] == -1) return;
    all_apply(2 * k, lz[k]);
    all_apply(2 * k + 1, lz[k]);
    lz[k] = -1;
  }
  void flush() {
    for (int k = 1; k < size; k++) push(k);
    history.clear();
  }
  int add_history(T x) {
    if ((int)history.size() == history_limit) flush();
    vector<T> power;
    power.reserve(log + 1);
    power.push_back(x);
    for (int i = 0; i < log; i++) power.push_back(M::op(power.back(), power.back()));
    history.push_back(move(power));
    return (int)history.size() - 1;
  }

 public:
  RangeSetRangeProd() : RangeSetRangeProd(0) {}
  explicit RangeSetRangeProd(int n) : RangeSetRangeProd(vector<T>(n, M::e())) {}
  explicit RangeSetRangeProd(const vector<T>& v) : _n(int(v.size())) {
    size = 1, log = 0;
    while (size < _n) size <<= 1, log++;
    d = vector<T>(2 * size, M::e());
    lz = vector<int>(size, -1);
    height = vector<int>(2 * size);
    for (int k = size - 1; k > 0; k--) height[k] = height[2 * k] + 1;
    for (int i = 0; i < _n; i++) d[size + i] = v[i];
    for (int k = size - 1; k > 0; k--) update(k);
    history_limit = max(1, size / (log + 1));
  }

  void set(int p, T x) {
    assert(0 <= p && p < _n);
    p += size;
    for (int i = log; i >= 1; i--) push(p >> i);
    d[p] = x;
    for (int i = 1; i <= log; i++) update(p >> i);
  }
  T get(int p) {
    assert(0 <= p && p < _n);
    p += size;
    for (int i = log; i >= 1; i--) push(p >> i);
    return d[p];
  }
  T prod(int l, int r) {
    assert(0 <= l && l <= r && r <= _n);
    if (l == r) return M::e();
    l += size, r += size;
    for (int i = log; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    T sml = M::e(), smr = M::e();
    while (l < r) {
      if (l & 1) sml = M::op(sml, d[l++]);
      if (r & 1) smr = M::op(d[--r], smr);
      l >>= 1, r >>= 1;
    }
    return M::op(sml, smr);
  }
  T all_prod() { return d[1]; }
  void apply(int p, T x) { set(p, x); }
  void apply(int l, int r, T x) {
    assert(0 <= l && l <= r && r <= _n);
    if (l == r) return;
    int id = add_history(x);
    l += size, r += size;
    for (int i = log; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    {
      int l2 = l, r2 = r;
      while (l < r) {
        if (l & 1) all_apply(l++, id);
        if (r & 1) all_apply(--r, id);
        l >>= 1, r >>= 1;
      }
      l = l2, r = r2;
    }
    for (int i = 1; i <= log; i++) {
      if (((l >> i) << i) != l) update(l >> i);
      if (((r >> i) << i) != r) update((r - 1) >> i);
    }
  }
  template <bool (*g)(T)>
  int max_right(int l) {
    return max_right(l, [](T x) { return g(x); });
  }
  template <class G>
  int max_right(int l, G g) {
    assert(0 <= l && l <= _n);
    assert(g(M::e()));
    if (l == _n) return _n;
    l += size;
    for (int i = log; i >= 1; i--) push(l >> i);
    T sm = M::e();
    do {
      while (l % 2 == 0) l >>= 1;
      if (!g(M::op(sm, d[l]))) {
        while (l < size) {
          push(l);
          l = 2 * l;
          if (g(M::op(sm, d[l]))) sm = M::op(sm, d[l++]);
        }
        return l - size;
      }
      sm = M::op(sm, d[l++]);
    } while ((l & -l) != l);
    return _n;
  }

  template <bool (*g)(T)>
  int min_left(int r) {
    return min_left(r, [](T x) { return g(x); });
  }
  template <class G>
  int min_left(int r, G g) {
    assert(0 <= r && r <= _n);
    assert(g(M::e()));
    if (r == 0) return 0;
    r += size;
    for (int i = log; i >= 1; i--) push((r - 1) >> i);
    T sm = M::e();
    do {
      r--;
      while (r > 1 && (r % 2)) r >>= 1;
      if (!g(M::op(d[r], sm))) {
        while (r < size) {
          push(r);
          r = 2 * r + 1;
          if (g(M::op(d[r], sm))) sm = M::op(d[r--], sm);
        }
        return r + 1 - size;
      }
      sm = M::op(d[r], sm);
    } while ((r & -r) != r);
    return 0;
  }
};

/**
 * @brief Range Set Range Prod
 * @docs docs/segment-tree/range-set-range-prod.md
 */
#line 2 "algebraic-structure/util.hpp"
#ifdef __cpp_concepts
#define REQUIRES(...) requires __VA_ARGS__
#else
#define REQUIRES(...)
#endif
#line 3 "algebraic-structure/magma.hpp"

#ifdef __cpp_concepts
template <class M>
concept Magma = requires(typename M::value_type x, typename M::value_type y) {
  typename M::value_type;
  { M::op(x, y) } -> same_as<typename M::value_type>;
};
#endif

template <class T>
struct AddMagma {
  using value_type = T;
  static T op(T x, T y) { return x + y; }
};
template <class T>
struct MulMagma {
  using value_type = T;
  static T op(T x, T y) { return x * y; }
};
template <class T, T id>
struct MaxMagma {
  using value_type = T;
  static T op(T x, T y) { return x > y ? x : y; }
};
template <class T, T id>
struct MinMagma {
  using value_type = T;
  static T op(T x, T y) { return x < y ? x : y; }
};
#line 3 "algebraic-structure/monoid.hpp"

#ifdef __cpp_concepts
template <class M>
concept Monoid = Magma<M> && requires {
  { M::e() } -> same_as<typename M::value_type>;
};
#endif

template <class T>
struct AddMonoid {
  using value_type = T;
  static T op(T x, T y) { return x + y; }
  static T e() { return T(0); }
};
template <class T>
struct MulMonoid {
  using value_type = T;
  static T op(T x, T y) { return x * y; }
  static T e() { return T(1); }
};
template <class T, T id>
struct MaxMonoid {
  using value_type = T;
  static T op(T x, T y) { return x > y ? x : y; }
  static T e() { return id; }
};
template <class T, T id>
struct MinMonoid {
  using value_type = T;
  static T op(T x, T y) { return x < y ? x : y; }
  static T e() { return id; }
};
#line 3 "segment-tree/range-set-range-prod.hpp"

template <class M>
REQUIRES(Monoid<M>)
struct RangeSetRangeProd {
  using T = typename M::value_type;

 private:
  int _n, size, log, history_limit;
  vector<T> d;
  vector<int> lz, height;
  vector<vector<T>> history;

  void update(int k) { d[k] = M::op(d[2 * k], d[2 * k + 1]); }
  void all_apply(int k, int id) {
    d[k] = history[id][height[k]];
    if (k < size) lz[k] = id;
  }
  void push(int k) {
    if (lz[k] == -1) return;
    all_apply(2 * k, lz[k]);
    all_apply(2 * k + 1, lz[k]);
    lz[k] = -1;
  }
  void flush() {
    for (int k = 1; k < size; k++) push(k);
    history.clear();
  }
  int add_history(T x) {
    if ((int)history.size() == history_limit) flush();
    vector<T> power;
    power.reserve(log + 1);
    power.push_back(x);
    for (int i = 0; i < log; i++) power.push_back(M::op(power.back(), power.back()));
    history.push_back(move(power));
    return (int)history.size() - 1;
  }

 public:
  RangeSetRangeProd() : RangeSetRangeProd(0) {}
  explicit RangeSetRangeProd(int n) : RangeSetRangeProd(vector<T>(n, M::e())) {}
  explicit RangeSetRangeProd(const vector<T>& v) : _n(int(v.size())) {
    size = 1, log = 0;
    while (size < _n) size <<= 1, log++;
    d = vector<T>(2 * size, M::e());
    lz = vector<int>(size, -1);
    height = vector<int>(2 * size);
    for (int k = size - 1; k > 0; k--) height[k] = height[2 * k] + 1;
    for (int i = 0; i < _n; i++) d[size + i] = v[i];
    for (int k = size - 1; k > 0; k--) update(k);
    history_limit = max(1, size / (log + 1));
  }

  void set(int p, T x) {
    assert(0 <= p && p < _n);
    p += size;
    for (int i = log; i >= 1; i--) push(p >> i);
    d[p] = x;
    for (int i = 1; i <= log; i++) update(p >> i);
  }
  T get(int p) {
    assert(0 <= p && p < _n);
    p += size;
    for (int i = log; i >= 1; i--) push(p >> i);
    return d[p];
  }
  T prod(int l, int r) {
    assert(0 <= l && l <= r && r <= _n);
    if (l == r) return M::e();
    l += size, r += size;
    for (int i = log; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    T sml = M::e(), smr = M::e();
    while (l < r) {
      if (l & 1) sml = M::op(sml, d[l++]);
      if (r & 1) smr = M::op(d[--r], smr);
      l >>= 1, r >>= 1;
    }
    return M::op(sml, smr);
  }
  T all_prod() { return d[1]; }
  void apply(int p, T x) { set(p, x); }
  void apply(int l, int r, T x) {
    assert(0 <= l && l <= r && r <= _n);
    if (l == r) return;
    int id = add_history(x);
    l += size, r += size;
    for (int i = log; i >= 1; i--) {
      if (((l >> i) << i) != l) push(l >> i);
      if (((r >> i) << i) != r) push((r - 1) >> i);
    }
    {
      int l2 = l, r2 = r;
      while (l < r) {
        if (l & 1) all_apply(l++, id);
        if (r & 1) all_apply(--r, id);
        l >>= 1, r >>= 1;
      }
      l = l2, r = r2;
    }
    for (int i = 1; i <= log; i++) {
      if (((l >> i) << i) != l) update(l >> i);
      if (((r >> i) << i) != r) update((r - 1) >> i);
    }
  }
  template <bool (*g)(T)>
  int max_right(int l) {
    return max_right(l, [](T x) { return g(x); });
  }
  template <class G>
  int max_right(int l, G g) {
    assert(0 <= l && l <= _n);
    assert(g(M::e()));
    if (l == _n) return _n;
    l += size;
    for (int i = log; i >= 1; i--) push(l >> i);
    T sm = M::e();
    do {
      while (l % 2 == 0) l >>= 1;
      if (!g(M::op(sm, d[l]))) {
        while (l < size) {
          push(l);
          l = 2 * l;
          if (g(M::op(sm, d[l]))) sm = M::op(sm, d[l++]);
        }
        return l - size;
      }
      sm = M::op(sm, d[l++]);
    } while ((l & -l) != l);
    return _n;
  }

  template <bool (*g)(T)>
  int min_left(int r) {
    return min_left(r, [](T x) { return g(x); });
  }
  template <class G>
  int min_left(int r, G g) {
    assert(0 <= r && r <= _n);
    assert(g(M::e()));
    if (r == 0) return 0;
    r += size;
    for (int i = log; i >= 1; i--) push((r - 1) >> i);
    T sm = M::e();
    do {
      r--;
      while (r > 1 && (r % 2)) r >>= 1;
      if (!g(M::op(d[r], sm))) {
        while (r < size) {
          push(r);
          r = 2 * r + 1;
          if (g(M::op(d[r], sm))) sm = M::op(d[r--], sm);
        }
        return r + 1 - size;
      }
      sm = M::op(d[r], sm);
    } while ((r & -r) != r);
    return 0;
  }
};

/**
 * @brief Range Set Range Prod
 * @docs docs/segment-tree/range-set-range-prod.md
 */
Back to top page