This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub maspypy/library
#include "ds/static_range_product.hpp"
#include "ds/sparse_table/sparse_table.hpp" #include "ds/sparse_table/disjoint_sparse_table.hpp" /* 参考:https://judge.yosupo.jp/submission/106668 長さ 2^LOG のブロックに分ける.ブロック内の prefix, suffix を持つ. ブロック積の列を ST(DST) で持つ.ブロックをまたぐ積は O(1). 短いものは O(1) を諦めて愚直ということにする. 前計算:O(Nlog(N)/2^LOG) クエリ:O(1) / worst O(2^LOG) */ template <typename Monoid, typename SPARSE_TABLE, int LOG = 4> struct Static_Range_Product { using MX = Monoid; using X = typename MX::value_type; int N, b_num; vc<X> A, pre, suf; // inclusive SPARSE_TABLE ST; Static_Range_Product() {} template <typename F> Static_Range_Product(int n, F f) { build(n, f); } Static_Range_Product(const vc<X>& v) { build(v); } void build(const vc<X>& v) { build(len(v), [&](int i) -> X { return v[i]; }); } template <typename F> void build(int m, F f) { N = m; b_num = N >> LOG; A.resize(N); FOR(i, N) A[i] = f(i); pre = A, suf = A; constexpr int mask = (1 << LOG) - 1; FOR(i, 1, N) { if (i & mask) pre[i] = MX::op(pre[i - 1], A[i]); } FOR_R(i, 1, N) { if (i & mask) suf[i - 1] = MX::op(A[i - 1], suf[i]); } ST.build(b_num, [&](int i) -> X { return suf[i << LOG]; }); } // O(1) or O(R-L) X prod(int L, int R) { if (L == R) return MX::unit(); R -= 1; int a = L >> LOG, b = R >> LOG; if (a < b) { X x = ST.prod(a + 1, b); x = MX::op(suf[L], x); x = MX::op(x, pre[R]); return x; } X x = A[L]; FOR(i, L + 1, R + 1) x = MX::op(x, A[i]); return x; } };
#line 2 "ds/sparse_table/sparse_table.hpp" // 冪等なモノイドであることを仮定。disjoint sparse table より x 倍高速 template <class Monoid> struct Sparse_Table { using MX = Monoid; using X = typename MX::value_type; int n, log; vvc<X> dat; Sparse_Table() {} Sparse_Table(int n) { build(n); } template <typename F> Sparse_Table(int n, F f) { build(n, f); } Sparse_Table(const vc<X>& v) { build(v); } void build(int m) { build(m, [](int i) -> X { return MX::unit(); }); } void build(const vc<X>& v) { build(len(v), [&](int i) -> X { return v[i]; }); } template <typename F> void build(int m, F f) { n = m, log = 1; while ((1 << log) < n) ++log; dat.resize(log); dat[0].resize(n); FOR(i, n) dat[0][i] = f(i); FOR(i, log - 1) { dat[i + 1].resize(len(dat[i]) - (1 << i)); FOR(j, len(dat[i]) - (1 << i)) { dat[i + 1][j] = MX::op(dat[i][j], dat[i][j + (1 << i)]); } } } X prod(int L, int R) { if (L == R) return MX::unit(); if (R == L + 1) return dat[0][L]; int k = topbit(R - L - 1); return MX::op(dat[k][L], dat[k][R - (1 << k)]); } template <class F> int max_right(const F check, int L) { assert(0 <= L && L <= n && check(MX::unit())); if (L == n) return n; int ok = L, ng = n + 1; while (ok + 1 < ng) { int k = (ok + ng) / 2; bool bl = check(prod(L, k)); if (bl) ok = k; if (!bl) ng = k; } return ok; } template <class F> int min_left(const F check, int R) { assert(0 <= R && R <= n && check(MX::unit())); if (R == 0) return 0; int ok = R, ng = -1; while (ng + 1 < ok) { int k = (ok + ng) / 2; bool bl = check(prod(k, R)); if (bl) ok = k; if (!bl) ng = k; } return ok; } }; #line 2 "ds/sparse_table/disjoint_sparse_table.hpp" template <class Monoid> struct Disjoint_Sparse_Table { using MX = Monoid; using X = typename MX::value_type; int n, log; vvc<X> dat; Disjoint_Sparse_Table() {} Disjoint_Sparse_Table(int n) { build(n); } template <typename F> Disjoint_Sparse_Table(int n, F f) { build(n, f); } Disjoint_Sparse_Table(const vc<X>& v) { build(v); } void build(int m) { build(m, [](int i) -> X { return MX::unit(); }); } void build(const vc<X>& v) { build(len(v), [&](int i) -> X { return v[i]; }); } template <typename F> void build(int m, F f) { n = m, log = 1; while ((1 << log) < n) ++log; dat.resize(log); dat[0].reserve(n); FOR(i, n) dat[0].eb(f(i)); FOR(i, 1, log) { auto& v = dat[i]; v = dat[0]; int b = 1 << i; for (int m = b; m <= n; m += 2 * b) { int L = m - b, R = min(n, m + b); FOR_R(j, L + 1, m) v[j - 1] = MX::op(v[j - 1], v[j]); FOR(j, m, R - 1) v[j + 1] = MX::op(v[j], v[j + 1]); } } } X prod(int L, int R) { if (L == R) return MX::unit(); --R; if (L == R) return dat[0][L]; int k = topbit(L ^ R); return MX::op(dat[k][L], dat[k][R]); } template <class F> int max_right(const F check, int L) { assert(0 <= L && L <= n && check(MX::unit())); if (L == n) return n; int ok = L, ng = n + 1; while (ok + 1 < ng) { int k = (ok + ng) / 2; bool bl = check(prod(L, k)); if (bl) ok = k; if (!bl) ng = k; } return ok; } template <class F> int min_left(const F check, int R) { assert(0 <= R && R <= n && check(MX::unit())); if (R == 0) return 0; int ok = R, ng = -1; while (ng + 1 < ok) { int k = (ok + ng) / 2; bool bl = check(prod(k, R)); if (bl) ok = k; if (!bl) ng = k; } return ok; } }; #line 3 "ds/static_range_product.hpp" /* 参考:https://judge.yosupo.jp/submission/106668 長さ 2^LOG のブロックに分ける.ブロック内の prefix, suffix を持つ. ブロック積の列を ST(DST) で持つ.ブロックをまたぐ積は O(1). 短いものは O(1) を諦めて愚直ということにする. 前計算:O(Nlog(N)/2^LOG) クエリ:O(1) / worst O(2^LOG) */ template <typename Monoid, typename SPARSE_TABLE, int LOG = 4> struct Static_Range_Product { using MX = Monoid; using X = typename MX::value_type; int N, b_num; vc<X> A, pre, suf; // inclusive SPARSE_TABLE ST; Static_Range_Product() {} template <typename F> Static_Range_Product(int n, F f) { build(n, f); } Static_Range_Product(const vc<X>& v) { build(v); } void build(const vc<X>& v) { build(len(v), [&](int i) -> X { return v[i]; }); } template <typename F> void build(int m, F f) { N = m; b_num = N >> LOG; A.resize(N); FOR(i, N) A[i] = f(i); pre = A, suf = A; constexpr int mask = (1 << LOG) - 1; FOR(i, 1, N) { if (i & mask) pre[i] = MX::op(pre[i - 1], A[i]); } FOR_R(i, 1, N) { if (i & mask) suf[i - 1] = MX::op(A[i - 1], suf[i]); } ST.build(b_num, [&](int i) -> X { return suf[i << LOG]; }); } // O(1) or O(R-L) X prod(int L, int R) { if (L == R) return MX::unit(); R -= 1; int a = L >> LOG, b = R >> LOG; if (a < b) { X x = ST.prod(a + 1, b); x = MX::op(suf[L], x); x = MX::op(x, pre[R]); return x; } X x = A[L]; FOR(i, L + 1, R + 1) x = MX::op(x, A[i]); return x; } };