library

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

View the Project on GitHub maspypy/library

:heavy_check_mark: ds/sqrt_tree.hpp

Verified with

Code

// 折角なので作ってみたが,使わなさそう
template <typename Monoid>
struct SQRT_Tree {
  using MX = Monoid;
  using X = typename MX::value_type;

  static constexpr int K = 3;
  static constexpr u32 SZ[] = {8, 64, 4096};
  static constexpr u32 MASK[] = {7, 63, 4095};

  int N;
  // 元となる静的な列
  vc<X> A;
  // 各階層に対して,ブロック先頭からある要素まで [s,i]
  // 各階層に対して,ある要素からブロック末尾まで [i,t]
  vvc<X> PREF, SUFF;
  // 各階層に対して,あるブロックからあるブロックまで
  vvc<X> BETWEEN;

  SQRT_Tree() {}
  template <typename F>
  SQRT_Tree(int n, F f) {
    build(n, f);
  }
  SQRT_Tree(const vc<X>& v) {
    build(len(v), [&](int i) -> X { return v[i]; });
  }

  template <typename F>
  void build(int n_, F f) {
    N = n_;
    assert(N <= (1 << 24));
    A.reserve(N);
    FOR(i, N) A.eb(f(i));
    // まず prefix, suffix の構築
    PREF.assign(K, A), SUFF.assign(K, A);
    FOR(k, K) {
      FOR(i, N) {
        if (i & MASK[k]) PREF[k][i] = MX::op(PREF[k][i - 1], A[i]);
      }
      FOR_R(i, N) {
        if (i & MASK[k]) SUFF[k][i - 1] = MX::op(A[i - 1], SUFF[k][i]);
      }
    }
    // between の構築
    BETWEEN.resize(K);
    FOR(k, K) {
      // n : 全体の小ブロックの個数
      auto get = [&](int i) -> X { return SUFF[k][SZ[k] * i]; };
      int n = N / SZ[k];
      int s = 0;
      FOR(r, n) {
        if (r % SZ[k] == 0) s = r;
        BETWEEN[k].eb(get(r));
        FOR_R(l, s, r) { BETWEEN[k].eb(MX::op(get(l), BETWEEN[k].back())); }
      }
    }
  }

  static constexpr int BIT_TO_LAYER[] = {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2,
                                         3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};

  X prod(int L, int R) {
    assert(0 <= L && L <= R && R <= N);
    if (L == R) return MX::unit();
    if (L + 1 == R) return A[L];
    --R;
    int k = BIT_TO_LAYER[topbit(L ^ R)];
    if (k == 0) {
      // 長さ SZ[0] のブロックにクエリが収まっている. 愚直に.
      X x = A[L];
      FOR(i, L + 1, R + 1) x = MX::op(x, A[i]);
      return x;
    }
    --k;
    // 同じ長さ SZ[k+1] のブロック内にある. 違う SZ[k] ブロック内にある.
    u32 a = L / SZ[k], b = R / SZ[k];
    assert(a < b);
    X &x1 = SUFF[k][L], &x2 = PREF[k][R];
    if (a + 1 == b) return MX::op(x1, x2);
    ++a, --b;
    // [a,b] 番目の SZ[k]-block の間を取得する
    // BETWEEN のどこにデータが置いてあるか調べる
    u32 m = a / SZ[k];
    a &= MASK[k], b &= MASK[k];
    u32 idx = m * (SZ[k] / 2) * (SZ[k] + 1);
    idx += (b + 1) * (b + 2) / 2 - 1 - a;
    return MX::op(x1, MX::op(BETWEEN[k][idx], x2));
  }
};
#line 1 "ds/sqrt_tree.hpp"

// 折角なので作ってみたが,使わなさそう
template <typename Monoid>
struct SQRT_Tree {
  using MX = Monoid;
  using X = typename MX::value_type;

  static constexpr int K = 3;
  static constexpr u32 SZ[] = {8, 64, 4096};
  static constexpr u32 MASK[] = {7, 63, 4095};

  int N;
  // 元となる静的な列
  vc<X> A;
  // 各階層に対して,ブロック先頭からある要素まで [s,i]
  // 各階層に対して,ある要素からブロック末尾まで [i,t]
  vvc<X> PREF, SUFF;
  // 各階層に対して,あるブロックからあるブロックまで
  vvc<X> BETWEEN;

  SQRT_Tree() {}
  template <typename F>
  SQRT_Tree(int n, F f) {
    build(n, f);
  }
  SQRT_Tree(const vc<X>& v) {
    build(len(v), [&](int i) -> X { return v[i]; });
  }

  template <typename F>
  void build(int n_, F f) {
    N = n_;
    assert(N <= (1 << 24));
    A.reserve(N);
    FOR(i, N) A.eb(f(i));
    // まず prefix, suffix の構築
    PREF.assign(K, A), SUFF.assign(K, A);
    FOR(k, K) {
      FOR(i, N) {
        if (i & MASK[k]) PREF[k][i] = MX::op(PREF[k][i - 1], A[i]);
      }
      FOR_R(i, N) {
        if (i & MASK[k]) SUFF[k][i - 1] = MX::op(A[i - 1], SUFF[k][i]);
      }
    }
    // between の構築
    BETWEEN.resize(K);
    FOR(k, K) {
      // n : 全体の小ブロックの個数
      auto get = [&](int i) -> X { return SUFF[k][SZ[k] * i]; };
      int n = N / SZ[k];
      int s = 0;
      FOR(r, n) {
        if (r % SZ[k] == 0) s = r;
        BETWEEN[k].eb(get(r));
        FOR_R(l, s, r) { BETWEEN[k].eb(MX::op(get(l), BETWEEN[k].back())); }
      }
    }
  }

  static constexpr int BIT_TO_LAYER[] = {0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2,
                                         3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};

  X prod(int L, int R) {
    assert(0 <= L && L <= R && R <= N);
    if (L == R) return MX::unit();
    if (L + 1 == R) return A[L];
    --R;
    int k = BIT_TO_LAYER[topbit(L ^ R)];
    if (k == 0) {
      // 長さ SZ[0] のブロックにクエリが収まっている. 愚直に.
      X x = A[L];
      FOR(i, L + 1, R + 1) x = MX::op(x, A[i]);
      return x;
    }
    --k;
    // 同じ長さ SZ[k+1] のブロック内にある. 違う SZ[k] ブロック内にある.
    u32 a = L / SZ[k], b = R / SZ[k];
    assert(a < b);
    X &x1 = SUFF[k][L], &x2 = PREF[k][R];
    if (a + 1 == b) return MX::op(x1, x2);
    ++a, --b;
    // [a,b] 番目の SZ[k]-block の間を取得する
    // BETWEEN のどこにデータが置いてあるか調べる
    u32 m = a / SZ[k];
    a &= MASK[k], b &= MASK[k];
    u32 idx = m * (SZ[k] / 2) * (SZ[k] + 1);
    idx += (b + 1) * (b + 2) / 2 - 1 - a;
    return MX::op(x1, MX::op(BETWEEN[k][idx], x2));
  }
};
Back to top page