This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "data-structure/wavelet-matrix/WaveletMatrixDualBinaryIndexedTree.hpp"
Wavelet Matrixと双対BITを同時に持つことで、数列に対して高度な加算・一点取得のクエリを処理できるようにしたデータ構造。
(1) WaveletMatrix<S, T> wm(vector<T> v)
(2) WaveletMatrix<S, T> wm(vector<T> v, vector<S> w)
長さ n = v.size()
の数列 v
に対してWavelet Matrixを構築する。
v
からビットベクトルと双対BITを構築する。v
からビットベクトル、数列 w
から双対BITを構築する。void wm.range_add(int l, int r, T mink, T maxk, S x)
(1) $l\leq i \lt r$ かつ $mink \leq v_i \lt maxk$ を満たすすべての $i$ において、双対BITで表される数列の $i$ 番目のインデックスの要素に x
を加算する。 v[i]
の要素は変更しない。
例として、v = {3, 1, 4, 1, 5, 9}
ならば、
// 初期状態: {3, 1, 4, 1, 5, 9}
void wm.range_add(1, 5, 2, 5, 10) // {3, 1, 14, 1, 5, 9}
void wm.range_add(0, 4, 1, 4, 10) // {13, 11, 14, 11, 5, 9}
のようになる。
(2) $l\leq i \lt r$ かつ $mink \leq v_i \lt maxk$ を満たすすべての $i$ において、双対BITで表される数列の $i$ 番目のインデックスの要素に x
を加算する。v[i]
の要素は変更しない。
例として、v = {3, 1, 4, 1, 5, 9}
、 w = {2, 7, 1, 8, 2, 8}
ならば、
// 初期状態: {2, 7, 1, 8, 2, 8}
void wm.range_add(1, 5, 2, 6, 10) // {2, 7, 11, 8, 12, 8}
void wm.range_add(2, 6, 1, 5, 10) // {2, 7, 21, 18, 12, 8}
のようになる。
std::numeric_limits<T>::min()
$\leq mink \leq maxk \leq$ std::numeric_limits<T>::max()
S wm.get(int p)
(1) (2) 双対BITで表される数列の p
番目の値を返す。
#include "../binary-indexed-tree/DualBinaryIndexedTree.hpp"
struct BitVector {
unsigned sz;
unsigned blocksize;
vector<unsigned> bit, sum;
BitVector() {}
BitVector(unsigned siz) {
sz = siz;
blocksize = (sz + 31) >> 5;
bit.assign(blocksize, 0U);
sum.assign(blocksize, 0U);
}
inline void set(int k) { bit[k >> 5] |= 1U << (k & 31); }
inline void build() {
sum[0] = 0U;
for (int i = 1; i < blocksize; i++) {
sum[i] = sum[i - 1] + __builtin_popcount(bit[i - 1]);
}
}
inline bool access(unsigned k) {
return (bool((bit[k >> 5] >> (k & 31)) & 1));
}
inline int rank(int k) {
return (sum[k >> 5] + __builtin_popcount(bit[k >> 5] & ((1U << (k & 31)) - 1)));
}
};
template <class S, class T>
class WaveletMatrix {
private:
unsigned n;
unsigned bitsize;
vector<BitVector> b;
vector<unsigned> zero;
vector<T> cmp;
vector<S> arr;
vector<RangeAddPointGet<S>> fen;
inline unsigned compress(const T &x) {
return lower_bound(cmp.begin(), cmp.end(), x) - begin(cmp);
}
public:
// コンストラクタ
WaveletMatrix() {}
WaveletMatrix(vector<T> v) {
n = v.size();
arr = v;
cmp = v;
sort(cmp.begin(), cmp.end());
cmp.erase(unique(cmp.begin(), cmp.end()), cmp.end());
vector<T> tmpc(n);
vector<T> compressed(n);
for (unsigned i = 0; i < n; i++) {
compressed[i] = distance(cmp.begin(), lower_bound(cmp.begin(), cmp.end(), v[i]));
}
bitsize = bit_width(cmp.size());
b.resize(bitsize + 1);
fen.resize(bitsize + 1, RangeAddPointGet<S>(n));
zero.resize(bitsize, 0);
int cur = 0;
for (unsigned i = 0; i < bitsize; i++) {
b[i] = BitVector(n + 1);
cur = 0;
for (unsigned j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
b[i].set(j);
} else {
zero[i]++;
tmpc[cur] = compressed[j];
cur++;
}
}
b[i].build();
for (int j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
tmpc[cur] = compressed[j];
cur++;
}
}
swap(tmpc, compressed);
}
b[bitsize] = BitVector(n + 1);
}
WaveletMatrix(vector<T> v, vector<S> w) {
n = v.size();
arr = w;
cmp = v;
sort(cmp.begin(), cmp.end());
cmp.erase(unique(cmp.begin(), cmp.end()), cmp.end());
vector<T> tmpc(n);
vector<T> compressed(n);
for (unsigned i = 0; i < n; i++) {
compressed[i] = distance(cmp.begin(), lower_bound(cmp.begin(), cmp.end(), v[i]));
}
bitsize = bit_width(cmp.size());
fen.resize(bitsize + 1, RangeAddPointGet<S>(n));
b.resize(bitsize + 1);
zero.resize(bitsize, 0);
int cur = 0;
for (unsigned i = 0; i < bitsize; i++) {
b[i] = BitVector(n + 1);
cur = 0;
for (unsigned j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
b[i].set(j);
} else {
zero[i]++;
tmpc[cur] = compressed[j];
cur++;
}
}
b[i].build();
for (int j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
tmpc[cur] = compressed[j];
cur++;
}
}
swap(tmpc, compressed);
}
b[bitsize] = BitVector(n + 1);
}
S get(unsigned k) {
S val = arr[k];
unsigned cur = k;
for (unsigned i = 0; i < bitsize; i++) {
val += fen[i].point_get(cur);
if (b[i].access(cur)) {
cur = zero[i] + b[i].rank(cur);
} else {
cur -= b[i].rank(cur);
}
}
val += fen[bitsize].point_get(cur);
return val;
}
void range_add(int l, int r, T mink, T maxk, S x) {
int D = compress(mink);
int U = compress(maxk);
auto dfs = [&](auto &rec, int d, int L, int R, int A, int B) -> void {
if (U <= A or B <= D) return;
if (D <= A and B <= U) {
fen[d].range_add(L, R, x);
return;
}
if (d == bitsize) {
if (D <= A and A < U) {
fen[bitsize].range_add(L, R, x);
}
return;
}
int C = (A + B) >> 1;
int rank0_l = L - b[d].rank(L);
int rank0_r = R - b[d].rank(R);
int rank1_l = b[d].rank(L) + zero[d];
int rank1_r = b[d].rank(R) + zero[d];
rec(rec, d + 1, rank0_l, rank0_r, A, C);
rec(rec, d + 1, rank1_l, rank1_r, C, B);
};
dfs(dfs, 0, l, r, 0, 1 << bitsize);
}
};
#line 1 "data-structure/binary-indexed-tree/DualBinaryIndexedTree.hpp"
template <class T>
struct RangeAddPointGet {
private:
fenwick_tree<T> ft;
public:
RangeAddPointGet() {}
RangeAddPointGet(int siz) : ft(siz + 1) {}
void range_add(int l, int r, T x) {
ft.add(l, x);
ft.add(r, -x);
}
void add(int p, T x) {
ft.add(p, x);
ft.add(p + 1, -x);
}
T point_get(int p) {
return ft.sum(0, p + 1);
}
};
#line 2 "data-structure/wavelet-matrix/WaveletMatrixDualBinaryIndexedTree.hpp"
struct BitVector {
unsigned sz;
unsigned blocksize;
vector<unsigned> bit, sum;
BitVector() {}
BitVector(unsigned siz) {
sz = siz;
blocksize = (sz + 31) >> 5;
bit.assign(blocksize, 0U);
sum.assign(blocksize, 0U);
}
inline void set(int k) { bit[k >> 5] |= 1U << (k & 31); }
inline void build() {
sum[0] = 0U;
for (int i = 1; i < blocksize; i++) {
sum[i] = sum[i - 1] + __builtin_popcount(bit[i - 1]);
}
}
inline bool access(unsigned k) {
return (bool((bit[k >> 5] >> (k & 31)) & 1));
}
inline int rank(int k) {
return (sum[k >> 5] + __builtin_popcount(bit[k >> 5] & ((1U << (k & 31)) - 1)));
}
};
template <class S, class T>
class WaveletMatrix {
private:
unsigned n;
unsigned bitsize;
vector<BitVector> b;
vector<unsigned> zero;
vector<T> cmp;
vector<S> arr;
vector<RangeAddPointGet<S>> fen;
inline unsigned compress(const T &x) {
return lower_bound(cmp.begin(), cmp.end(), x) - begin(cmp);
}
public:
// コンストラクタ
WaveletMatrix() {}
WaveletMatrix(vector<T> v) {
n = v.size();
arr = v;
cmp = v;
sort(cmp.begin(), cmp.end());
cmp.erase(unique(cmp.begin(), cmp.end()), cmp.end());
vector<T> tmpc(n);
vector<T> compressed(n);
for (unsigned i = 0; i < n; i++) {
compressed[i] = distance(cmp.begin(), lower_bound(cmp.begin(), cmp.end(), v[i]));
}
bitsize = bit_width(cmp.size());
b.resize(bitsize + 1);
fen.resize(bitsize + 1, RangeAddPointGet<S>(n));
zero.resize(bitsize, 0);
int cur = 0;
for (unsigned i = 0; i < bitsize; i++) {
b[i] = BitVector(n + 1);
cur = 0;
for (unsigned j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
b[i].set(j);
} else {
zero[i]++;
tmpc[cur] = compressed[j];
cur++;
}
}
b[i].build();
for (int j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
tmpc[cur] = compressed[j];
cur++;
}
}
swap(tmpc, compressed);
}
b[bitsize] = BitVector(n + 1);
}
WaveletMatrix(vector<T> v, vector<S> w) {
n = v.size();
arr = w;
cmp = v;
sort(cmp.begin(), cmp.end());
cmp.erase(unique(cmp.begin(), cmp.end()), cmp.end());
vector<T> tmpc(n);
vector<T> compressed(n);
for (unsigned i = 0; i < n; i++) {
compressed[i] = distance(cmp.begin(), lower_bound(cmp.begin(), cmp.end(), v[i]));
}
bitsize = bit_width(cmp.size());
fen.resize(bitsize + 1, RangeAddPointGet<S>(n));
b.resize(bitsize + 1);
zero.resize(bitsize, 0);
int cur = 0;
for (unsigned i = 0; i < bitsize; i++) {
b[i] = BitVector(n + 1);
cur = 0;
for (unsigned j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
b[i].set(j);
} else {
zero[i]++;
tmpc[cur] = compressed[j];
cur++;
}
}
b[i].build();
for (int j = 0; j < n; j++) {
if (compressed[j] & (1U << (bitsize - i - 1))) {
tmpc[cur] = compressed[j];
cur++;
}
}
swap(tmpc, compressed);
}
b[bitsize] = BitVector(n + 1);
}
S get(unsigned k) {
S val = arr[k];
unsigned cur = k;
for (unsigned i = 0; i < bitsize; i++) {
val += fen[i].point_get(cur);
if (b[i].access(cur)) {
cur = zero[i] + b[i].rank(cur);
} else {
cur -= b[i].rank(cur);
}
}
val += fen[bitsize].point_get(cur);
return val;
}
void range_add(int l, int r, T mink, T maxk, S x) {
int D = compress(mink);
int U = compress(maxk);
auto dfs = [&](auto &rec, int d, int L, int R, int A, int B) -> void {
if (U <= A or B <= D) return;
if (D <= A and B <= U) {
fen[d].range_add(L, R, x);
return;
}
if (d == bitsize) {
if (D <= A and A < U) {
fen[bitsize].range_add(L, R, x);
}
return;
}
int C = (A + B) >> 1;
int rank0_l = L - b[d].rank(L);
int rank0_r = R - b[d].rank(R);
int rank1_l = b[d].rank(L) + zero[d];
int rank1_r = b[d].rank(R) + zero[d];
rec(rec, d + 1, rank0_l, rank0_r, A, C);
rec(rec, d + 1, rank1_l, rank1_r, C, B);
};
dfs(dfs, 0, l, r, 0, 1 << bitsize);
}
};