This documentation is automatically generated by online-judge-tools/verification-helper
#include "ds/wavelet_matrix/wavelet_matrix_old.hpp"
#include "ds/bit_vector.hpp"
// 座圧するかどうかを COMPRESS で指定する
// xor 的な使い方をする場合には、コンストラクタで log を渡すこと
template <typename T, bool COMPRESS, bool USE_SUM>
struct Wavelet_Matrix_Old {
static_assert(is_same_v<T, int> || is_same_v<T, ll>);
int N, lg;
vector<int> mid;
vector<Bit_Vector> bv;
vc<T> key;
bool set_log;
vvc<T> cumsum;
Wavelet_Matrix_Old() {}
// 和を使わないなら、SUM_data は空でよい
Wavelet_Matrix_Old(vc<T> A, vc<T> SUM_data = {}, int log = -1) {
build(A, SUM_data, log);
}
void build(vc<T> A, vc<T> SUM_data = {}, int log = -1) {
if constexpr (USE_SUM) { assert(len(SUM_data) == len(A)); }
N = len(A), lg = log, set_log = (log != -1);
if (N == 0) {
lg = 0;
cumsum.resize(1);
cumsum[0] = {0};
return;
}
vc<T>& S = SUM_data;
if (COMPRESS) {
assert(!set_log);
key.reserve(N);
vc<int> I = argsort(A);
for (auto&& i: I) {
if (key.empty() || key.back() != A[i]) key.eb(A[i]);
A[i] = len(key) - 1;
}
key.shrink_to_fit();
}
if (lg == -1) lg = __lg(max<ll>(MAX(A), 1)) + 1;
mid.resize(lg), bv.assign(lg, Bit_Vector(N));
if constexpr (USE_SUM) cumsum.assign(1 + lg, vc<T>(N + 1, 0));
S.resize(N);
vc<T> A0(N), A1(N);
vc<T> S0(N), S1(N);
FOR_R(d, -1, lg) {
int p0 = 0, p1 = 0;
if constexpr (USE_SUM) {
FOR(i, N) { cumsum[d + 1][i + 1] = cumsum[d + 1][i] + S[i]; }
}
if (d == -1) break;
FOR(i, N) {
bool f = (A[i] >> d & 1);
if (!f) {
if constexpr (USE_SUM) S0[p0] = S[i];
A0[p0++] = A[i];
} else {
if constexpr (USE_SUM) S1[p1] = S[i];
bv[d].set(i), A1[p1++] = A[i];
}
}
mid[d] = p0;
bv[d].build();
swap(A, A0), swap(S, S0);
FOR(i, p1) A[p0 + i] = A1[i], S[p0 + i] = S1[i];
}
}
// [L,R) x [a,b), (cnt, monoid value)
pair<int, T> range_cnt_sum(int L, int R, T a, T b, T xor_val = 0) {
if (xor_val != 0) assert(set_log);
if (a == b) return {0, 0};
if (COMPRESS) a = LB(key, a), b = LB(key, b);
int cnt = 0;
T sm = 0;
auto dfs = [&](auto& dfs, int d, int L, int R, T lx, T rx) -> void {
if (rx <= a || b <= lx) return;
if (a <= lx && rx <= b) {
cnt += R - L, sm += get(d, L, R);
return;
}
--d;
T mx = (lx + rx) / 2;
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
dfs(dfs, d, l0, r0, lx, mx), dfs(dfs, d, l1, r1, mx, rx);
};
dfs(dfs, lg, L, R, 0, T(1) << lg);
return {cnt, sm};
}
// smallest k, sum of [0,k)
pair<T, T> kth_value_sum(int L, int R, int k, T xor_val = 0) {
assert(0 <= k && k <= R - L);
if (k == R - L) { return {infty<T>, sum_all(L, R)}; }
if (L == R) return {infty<T>, 0};
if (xor_val != 0) assert(set_log);
T sm = 0, val = 0;
for (int d = lg - 1; d >= 0; --d) {
// いま幅 d+1 の trie node に居て, 幅 d のところに行く
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
if (k < r0 - l0) {
L = l0, R = r0;
} else {
k -= r0 - l0, val |= T(1) << d, L = l1, R = r1;
if constexpr (USE_SUM) sm += get(d, l0, r0);
}
}
if constexpr (USE_SUM) sm += get(0, L, L + k);
if (COMPRESS) val = key[val];
return {val, sm};
}
int count(int L, int R, T a, T b, T xor_val = 0) {
return range_cnt_sum(L, R, a, b, xor_val).fi;
}
T sum(int L, int R, T a, T b, T xor_val = 0) {
static_assert(USE_SUM);
return range_cnt_sum(L, R, a, b, xor_val).se;
}
T sum_index_range(int L, int R, int k1, int k2, T xor_val = 0) {
static_assert(USE_SUM);
return kth_value_sum(L, R, k2, xor_val).se
- kth_value_sum(L, R, k1, xor_val).se;
}
T kth(int L, int R, int k, T xor_val = 0) {
assert(0 <= k && k < R - L);
return kth_value_sum(L, R, k, xor_val).fi;
}
// x 以上最小 OR infty<T>
T next(int L, int R, T x, T xor_val = 0) {
if (xor_val != 0) assert(set_log);
if (L == R) return infty<T>;
if (COMPRESS) x = LB(key, x);
T ans = infty<T>;
auto dfs = [&](auto& dfs, int d, int L, int R, T lx, T rx) -> void {
if (ans <= lx || L == R || rx <= x) return;
if (d == 0) {
chmin(ans, lx);
return;
}
--d;
T mx = (lx + rx) / 2;
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
dfs(dfs, d, l0, r0, lx, mx), dfs(dfs, d, l1, r1, mx, rx);
};
dfs(dfs, lg, L, R, 0, T(1) << lg);
if (COMPRESS && ans < infty<T>) ans = key[ans];
return ans;
}
// x 以下最大 OR -infty<T>
T prev(int L, int R, T x, T xor_val = 0) {
if (xor_val != 0) assert(set_log);
if (L == R) return -infty<T>;
T ans = -infty<int>;
++x;
if (COMPRESS) x = LB(key, x);
auto dfs = [&](auto& dfs, int d, int L, int R, T lx, T rx) -> void {
if ((rx - 1) <= ans || L == R || x <= lx) return;
if (d == 0) {
chmax(ans, lx);
return;
}
--d;
T mx = (lx + rx) / 2;
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
dfs(dfs, d, l1, r1, mx, rx), dfs(dfs, d, l0, r0, lx, mx);
};
dfs(dfs, lg, L, R, 0, T(1) << lg);
if (COMPRESS && ans != -infty<T>) ans = key[ans];
return ans;
}
// xor した結果で、[L, R) の中で中央値。
// LOWER = true:下側中央値、false:上側中央値
T median(bool UPPER, int L, int R, T xor_val = 0) {
int n = R - L;
int k = (UPPER ? n / 2 : (n - 1) / 2);
return kth(L, R, k, xor_val);
}
T sum_all(int L, int R) { return get(lg, L, R); }
// check(cnt, prefix sum) が true となるような最大の (cnt, sum)
template <typename F>
pair<int, T> max_right(F check, int L, int R, T xor_val = 0) {
assert(check(0, 0));
if (xor_val != 0) assert(set_log);
if (L == R) return {0, 0};
if (check(R - L, get(lg, L, R))) return {R - L, get(lg, L, R)};
int cnt = 0;
T sm = 0;
for (int d = lg - 1; d >= 0; --d) {
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
if (check(cnt + r0 - l0, sm + get(d, l0, r0))) {
cnt += r0 - l0, sm += get(d, l0, r0);
L = l1, R = r1;
} else {
L = l0, R = r0;
}
}
int k = binary_search(
[&](int k) -> bool { return check(cnt + k, sm + get(0, L, L + k)); }, 0,
R - L);
cnt += k, sm += get(0, L, L + k);
return {cnt, sm};
}
private:
inline T get(int d, int L, int R) {
if constexpr (USE_SUM) return cumsum[d][R] - cumsum[d][L];
return 0;
}
};
#line 1 "ds/bit_vector.hpp"
struct Bit_Vector {
int n;
bool prepared = 0;
vc<pair<u64, u32>> dat;
Bit_Vector(int n) : n(n) { dat.assign((n + 127) >> 6, {0, 0}); }
void set(int i) {
assert(!prepared);
dat[i >> 6].fi |= u64(1) << (i & 63);
}
void reset() {
fill(all(dat), pair<u64, u32>{0, 0});
prepared = 0;
}
void build() {
prepared = 1;
FOR(i, len(dat) - 1) dat[i + 1].se = dat[i].se + popcnt(dat[i].fi);
}
// [0, k) 内の 1 の個数
bool operator[](int i) { return dat[i >> 6].fi >> (i & 63) & 1; }
int count_prefix(int k, bool f = true) {
assert(prepared);
auto [a, b] = dat[k >> 6];
int ret = b + popcnt(a & ((u64(1) << (k & 63)) - 1));
return (f ? ret : k - ret);
}
int count(int L, int R, bool f = true) { return count_prefix(R, f) - count_prefix(L, f); }
string to_string() {
string ans;
FOR(i, n) ans += '0' + (dat[i / 64].fi >> (i % 64) & 1);
return ans;
}
};
#line 2 "ds/wavelet_matrix/wavelet_matrix_old.hpp"
// 座圧するかどうかを COMPRESS で指定する
// xor 的な使い方をする場合には、コンストラクタで log を渡すこと
template <typename T, bool COMPRESS, bool USE_SUM>
struct Wavelet_Matrix_Old {
static_assert(is_same_v<T, int> || is_same_v<T, ll>);
int N, lg;
vector<int> mid;
vector<Bit_Vector> bv;
vc<T> key;
bool set_log;
vvc<T> cumsum;
Wavelet_Matrix_Old() {}
// 和を使わないなら、SUM_data は空でよい
Wavelet_Matrix_Old(vc<T> A, vc<T> SUM_data = {}, int log = -1) {
build(A, SUM_data, log);
}
void build(vc<T> A, vc<T> SUM_data = {}, int log = -1) {
if constexpr (USE_SUM) { assert(len(SUM_data) == len(A)); }
N = len(A), lg = log, set_log = (log != -1);
if (N == 0) {
lg = 0;
cumsum.resize(1);
cumsum[0] = {0};
return;
}
vc<T>& S = SUM_data;
if (COMPRESS) {
assert(!set_log);
key.reserve(N);
vc<int> I = argsort(A);
for (auto&& i: I) {
if (key.empty() || key.back() != A[i]) key.eb(A[i]);
A[i] = len(key) - 1;
}
key.shrink_to_fit();
}
if (lg == -1) lg = __lg(max<ll>(MAX(A), 1)) + 1;
mid.resize(lg), bv.assign(lg, Bit_Vector(N));
if constexpr (USE_SUM) cumsum.assign(1 + lg, vc<T>(N + 1, 0));
S.resize(N);
vc<T> A0(N), A1(N);
vc<T> S0(N), S1(N);
FOR_R(d, -1, lg) {
int p0 = 0, p1 = 0;
if constexpr (USE_SUM) {
FOR(i, N) { cumsum[d + 1][i + 1] = cumsum[d + 1][i] + S[i]; }
}
if (d == -1) break;
FOR(i, N) {
bool f = (A[i] >> d & 1);
if (!f) {
if constexpr (USE_SUM) S0[p0] = S[i];
A0[p0++] = A[i];
} else {
if constexpr (USE_SUM) S1[p1] = S[i];
bv[d].set(i), A1[p1++] = A[i];
}
}
mid[d] = p0;
bv[d].build();
swap(A, A0), swap(S, S0);
FOR(i, p1) A[p0 + i] = A1[i], S[p0 + i] = S1[i];
}
}
// [L,R) x [a,b), (cnt, monoid value)
pair<int, T> range_cnt_sum(int L, int R, T a, T b, T xor_val = 0) {
if (xor_val != 0) assert(set_log);
if (a == b) return {0, 0};
if (COMPRESS) a = LB(key, a), b = LB(key, b);
int cnt = 0;
T sm = 0;
auto dfs = [&](auto& dfs, int d, int L, int R, T lx, T rx) -> void {
if (rx <= a || b <= lx) return;
if (a <= lx && rx <= b) {
cnt += R - L, sm += get(d, L, R);
return;
}
--d;
T mx = (lx + rx) / 2;
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
dfs(dfs, d, l0, r0, lx, mx), dfs(dfs, d, l1, r1, mx, rx);
};
dfs(dfs, lg, L, R, 0, T(1) << lg);
return {cnt, sm};
}
// smallest k, sum of [0,k)
pair<T, T> kth_value_sum(int L, int R, int k, T xor_val = 0) {
assert(0 <= k && k <= R - L);
if (k == R - L) { return {infty<T>, sum_all(L, R)}; }
if (L == R) return {infty<T>, 0};
if (xor_val != 0) assert(set_log);
T sm = 0, val = 0;
for (int d = lg - 1; d >= 0; --d) {
// いま幅 d+1 の trie node に居て, 幅 d のところに行く
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
if (k < r0 - l0) {
L = l0, R = r0;
} else {
k -= r0 - l0, val |= T(1) << d, L = l1, R = r1;
if constexpr (USE_SUM) sm += get(d, l0, r0);
}
}
if constexpr (USE_SUM) sm += get(0, L, L + k);
if (COMPRESS) val = key[val];
return {val, sm};
}
int count(int L, int R, T a, T b, T xor_val = 0) {
return range_cnt_sum(L, R, a, b, xor_val).fi;
}
T sum(int L, int R, T a, T b, T xor_val = 0) {
static_assert(USE_SUM);
return range_cnt_sum(L, R, a, b, xor_val).se;
}
T sum_index_range(int L, int R, int k1, int k2, T xor_val = 0) {
static_assert(USE_SUM);
return kth_value_sum(L, R, k2, xor_val).se
- kth_value_sum(L, R, k1, xor_val).se;
}
T kth(int L, int R, int k, T xor_val = 0) {
assert(0 <= k && k < R - L);
return kth_value_sum(L, R, k, xor_val).fi;
}
// x 以上最小 OR infty<T>
T next(int L, int R, T x, T xor_val = 0) {
if (xor_val != 0) assert(set_log);
if (L == R) return infty<T>;
if (COMPRESS) x = LB(key, x);
T ans = infty<T>;
auto dfs = [&](auto& dfs, int d, int L, int R, T lx, T rx) -> void {
if (ans <= lx || L == R || rx <= x) return;
if (d == 0) {
chmin(ans, lx);
return;
}
--d;
T mx = (lx + rx) / 2;
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
dfs(dfs, d, l0, r0, lx, mx), dfs(dfs, d, l1, r1, mx, rx);
};
dfs(dfs, lg, L, R, 0, T(1) << lg);
if (COMPRESS && ans < infty<T>) ans = key[ans];
return ans;
}
// x 以下最大 OR -infty<T>
T prev(int L, int R, T x, T xor_val = 0) {
if (xor_val != 0) assert(set_log);
if (L == R) return -infty<T>;
T ans = -infty<int>;
++x;
if (COMPRESS) x = LB(key, x);
auto dfs = [&](auto& dfs, int d, int L, int R, T lx, T rx) -> void {
if ((rx - 1) <= ans || L == R || x <= lx) return;
if (d == 0) {
chmax(ans, lx);
return;
}
--d;
T mx = (lx + rx) / 2;
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
dfs(dfs, d, l1, r1, mx, rx), dfs(dfs, d, l0, r0, lx, mx);
};
dfs(dfs, lg, L, R, 0, T(1) << lg);
if (COMPRESS && ans != -infty<T>) ans = key[ans];
return ans;
}
// xor した結果で、[L, R) の中で中央値。
// LOWER = true:下側中央値、false:上側中央値
T median(bool UPPER, int L, int R, T xor_val = 0) {
int n = R - L;
int k = (UPPER ? n / 2 : (n - 1) / 2);
return kth(L, R, k, xor_val);
}
T sum_all(int L, int R) { return get(lg, L, R); }
// check(cnt, prefix sum) が true となるような最大の (cnt, sum)
template <typename F>
pair<int, T> max_right(F check, int L, int R, T xor_val = 0) {
assert(check(0, 0));
if (xor_val != 0) assert(set_log);
if (L == R) return {0, 0};
if (check(R - L, get(lg, L, R))) return {R - L, get(lg, L, R)};
int cnt = 0;
T sm = 0;
for (int d = lg - 1; d >= 0; --d) {
int l0 = bv[d].count(L, 0), r0 = bv[d].count(R, 0);
int l1 = L + mid[d] - l0, r1 = R + mid[d] - r0;
if (xor_val >> d & 1) swap(l0, l1), swap(r0, r1);
if (check(cnt + r0 - l0, sm + get(d, l0, r0))) {
cnt += r0 - l0, sm += get(d, l0, r0);
L = l1, R = r1;
} else {
L = l0, R = r0;
}
}
int k = binary_search(
[&](int k) -> bool { return check(cnt + k, sm + get(0, L, L + k)); }, 0,
R - L);
cnt += k, sm += get(0, L, L + k);
return {cnt, sm};
}
private:
inline T get(int d, int L, int R) {
if constexpr (USE_SUM) return cumsum[d][R] - cumsum[d][L];
return 0;
}
};