Skip to content

disjoint_sparse_table.hpp

SECTIONData Structure INCLUDEnoya/disjoint_sparse_table.hpp

预处理静态数组上任意可结合运算的区间乘积;不要求幂等,并以常数时间回答查询。

Complexity: Time: O(n log n) build and O(1) range product. Space: O(n log n).

跳到代码 · GitHub ↗

Implementation

当前头文件,省略 include guard;依赖见 #include

/// @complexity Time: O(n log n) build and O(1) range product.
/// Space: O(n log n).

#include <algorithm>
#include <cassert>
#include <vector>

namespace noya {

/// @brief Static O(1) range product for an arbitrary associative monoid.
template <class Monoid> struct disjoint_sparse_table {
  using value_type = typename Monoid::value_type;

  int n = 0;
  std::vector<value_type> a;
  std::vector<std::vector<value_type>> st;

  disjoint_sparse_table() = default;
  explicit disjoint_sparse_table(const std::vector<value_type> &arr) {
    build(arr);
  }

  /// @brief Rebuild the table in O(n log n).
  void build(const std::vector<value_type> &arr) {
    a = arr;
    n = int(a.size());
    int lg = n <= 1 ? 0 : highest_bit(unsigned(n - 1)) + 1;
    st.assign(lg, std::vector<value_type>(n, Monoid::unit()));
    for (int dep = 0; dep < lg; dep++) {
      int hf = 1 << dep;
      int blk = hf << 1;
      for (int st0 = 0; st0 < n; st0 += blk) {
        int mid = std::min(st0 + hf, n);
        int ed = std::min(st0 + blk, n);
        if (st0 < mid) {
          st[dep][mid - 1] = a[mid - 1];
          for (int i = mid - 2; i >= st0; i--) {
            st[dep][i] = Monoid::op(a[i], st[dep][i + 1]);
          }
        }
        if (mid < ed) {
          st[dep][mid] = a[mid];
          for (int i = mid + 1; i < ed; i++) {
            st[dep][i] = Monoid::op(st[dep][i - 1], a[i]);
          }
        }
      }
    }
  }

  /// @brief Return the monoid product over [l, r).
  value_type prod(int l, int r) const {
    assert(0 <= l && l <= r && r <= n);
    if (l == r) {
      return Monoid::unit();
    }
    if (l + 1 == r) {
      return a[l];
    }
    int dep = highest_bit(unsigned(l ^ (r - 1)));
    return Monoid::op(st[dep][l], st[dep][r - 1]);
  }

  /// @brief Largest right such that predicate(prod(left, right)) is true.
  template <class Predicate>
  int max_right(int l, Predicate f) const {
    assert(0 <= l && l <= n);
    assert(f(Monoid::unit()));
    int ok = l;
    int bad = n + 1;
    while (bad - ok > 1) {
      int mid = ok + (bad - ok) / 2;
      if (f(prod(l, mid))) {
        ok = mid;
      } else {
        bad = mid;
      }
    }
    return ok;
  }

  /// @brief Smallest left such that predicate(prod(left, right)) is true.
  template <class Predicate>
  int min_left(int r, Predicate f) const {
    assert(0 <= r && r <= n);
    assert(f(Monoid::unit()));
    int ok = r;
    int bad = -1;
    while (ok - bad > 1) {
      int mid = bad + (ok - bad) / 2;
      if (f(prod(mid, r))) {
        ok = mid;
      } else {
        bad = mid;
      }
    }
    return ok;
  }

private:
  static int highest_bit(unsigned val) {
    assert(val != 0);
    return 31 - __builtin_clz(val);
  }
};

} // namespace noya
#ifndef NOYA_DISJOINT_SPARSE_TABLE_HPP
#define NOYA_DISJOINT_SPARSE_TABLE_HPP 1

/// @complexity Time: O(n log n) build and O(1) range product.
/// Space: O(n log n).

#include <algorithm>
#include <cassert>
#include <vector>

namespace noya {

/// @brief Static O(1) range product for an arbitrary associative monoid.
template <class Monoid> struct disjoint_sparse_table {
  using value_type = typename Monoid::value_type;

  int n = 0;
  std::vector<value_type> a;
  std::vector<std::vector<value_type>> st;

  disjoint_sparse_table() = default;
  explicit disjoint_sparse_table(const std::vector<value_type> &arr) {
    build(arr);
  }

  /// @brief Rebuild the table in O(n log n).
  void build(const std::vector<value_type> &arr) {
    a = arr;
    n = int(a.size());
    int lg = n <= 1 ? 0 : highest_bit(unsigned(n - 1)) + 1;
    st.assign(lg, std::vector<value_type>(n, Monoid::unit()));
    for (int dep = 0; dep < lg; dep++) {
      int hf = 1 << dep;
      int blk = hf << 1;
      for (int st0 = 0; st0 < n; st0 += blk) {
        int mid = std::min(st0 + hf, n);
        int ed = std::min(st0 + blk, n);
        if (st0 < mid) {
          st[dep][mid - 1] = a[mid - 1];
          for (int i = mid - 2; i >= st0; i--) {
            st[dep][i] = Monoid::op(a[i], st[dep][i + 1]);
          }
        }
        if (mid < ed) {
          st[dep][mid] = a[mid];
          for (int i = mid + 1; i < ed; i++) {
            st[dep][i] = Monoid::op(st[dep][i - 1], a[i]);
          }
        }
      }
    }
  }

  /// @brief Return the monoid product over [l, r).
  value_type prod(int l, int r) const {
    assert(0 <= l && l <= r && r <= n);
    if (l == r) {
      return Monoid::unit();
    }
    if (l + 1 == r) {
      return a[l];
    }
    int dep = highest_bit(unsigned(l ^ (r - 1)));
    return Monoid::op(st[dep][l], st[dep][r - 1]);
  }

  /// @brief Largest right such that predicate(prod(left, right)) is true.
  template <class Predicate>
  int max_right(int l, Predicate f) const {
    assert(0 <= l && l <= n);
    assert(f(Monoid::unit()));
    int ok = l;
    int bad = n + 1;
    while (bad - ok > 1) {
      int mid = ok + (bad - ok) / 2;
      if (f(prod(l, mid))) {
        ok = mid;
      } else {
        bad = mid;
      }
    }
    return ok;
  }

  /// @brief Smallest left such that predicate(prod(left, right)) is true.
  template <class Predicate>
  int min_left(int r, Predicate f) const {
    assert(0 <= r && r <= n);
    assert(f(Monoid::unit()));
    int ok = r;
    int bad = -1;
    while (ok - bad > 1) {
      int mid = bad + (ok - bad) / 2;
      if (f(prod(mid, r))) {
        ok = mid;
      } else {
        bad = mid;
      }
    }
    return ok;
  }

private:
  static int highest_bit(unsigned val) {
    assert(val != 0);
    return 31 - __builtin_clz(val);
  }
};

} // namespace noya

#endif // NOYA_DISJOINT_SPARSE_TABLE_HPP
#include <algorithm>
#include <cassert>
#include <vector>

/// @complexity Time: O(n log n) build and O(1) range product.
/// Space: O(n log n).

namespace noya {

/// @brief Static O(1) range product for an arbitrary associative monoid.
template <class Monoid> struct disjoint_sparse_table {
  using value_type = typename Monoid::value_type;

  int n = 0;
  std::vector<value_type> a;
  std::vector<std::vector<value_type>> st;

  disjoint_sparse_table() = default;
  explicit disjoint_sparse_table(const std::vector<value_type> &arr) {
    build(arr);
  }

  /// @brief Rebuild the table in O(n log n).
  void build(const std::vector<value_type> &arr) {
    a = arr;
    n = int(a.size());
    int lg = n <= 1 ? 0 : highest_bit(unsigned(n - 1)) + 1;
    st.assign(lg, std::vector<value_type>(n, Monoid::unit()));
    for (int dep = 0; dep < lg; dep++) {
      int hf = 1 << dep;
      int blk = hf << 1;
      for (int st0 = 0; st0 < n; st0 += blk) {
        int mid = std::min(st0 + hf, n);
        int ed = std::min(st0 + blk, n);
        if (st0 < mid) {
          st[dep][mid - 1] = a[mid - 1];
          for (int i = mid - 2; i >= st0; i--) {
            st[dep][i] = Monoid::op(a[i], st[dep][i + 1]);
          }
        }
        if (mid < ed) {
          st[dep][mid] = a[mid];
          for (int i = mid + 1; i < ed; i++) {
            st[dep][i] = Monoid::op(st[dep][i - 1], a[i]);
          }
        }
      }
    }
  }

  /// @brief Return the monoid product over [l, r).
  value_type prod(int l, int r) const {
    assert(0 <= l && l <= r && r <= n);
    if (l == r) {
      return Monoid::unit();
    }
    if (l + 1 == r) {
      return a[l];
    }
    int dep = highest_bit(unsigned(l ^ (r - 1)));
    return Monoid::op(st[dep][l], st[dep][r - 1]);
  }

  /// @brief Largest right such that predicate(prod(left, right)) is true.
  template <class Predicate>
  int max_right(int l, Predicate f) const {
    assert(0 <= l && l <= n);
    assert(f(Monoid::unit()));
    int ok = l;
    int bad = n + 1;
    while (bad - ok > 1) {
      int mid = ok + (bad - ok) / 2;
      if (f(prod(l, mid))) {
        ok = mid;
      } else {
        bad = mid;
      }
    }
    return ok;
  }

  /// @brief Smallest left such that predicate(prod(left, right)) is true.
  template <class Predicate>
  int min_left(int r, Predicate f) const {
    assert(0 <= r && r <= n);
    assert(f(Monoid::unit()));
    int ok = r;
    int bad = -1;
    while (ok - bad > 1) {
      int mid = bad + (ok - bad) / 2;
      if (f(prod(mid, r))) {
        ok = mid;
      } else {
        bad = mid;
      }
    }
    return ok;
  }

private:
  static int highest_bit(unsigned val) {
    assert(val != 0);
    return 31 - __builtin_clz(val);
  }
};

} // namespace noya