要素の挿入・削除が可能な動的ウェーブレット行列
lib/data_structure/dynamic_wavelet_matrix.hpp
インクルード
#include "data_structure/dynamic_wavelet_matrix.hpp"
クラス
| 名前 | 説明 |
|---|---|
DynamicWaveletMatrix |
要素の挿入・削除が可能な動的ウェーブレット行列 |
検証
依存するヘッダ(5)
-
動的完備辞書
lib/internal/dynamic_bit_vector.hpp -
疑似乱数生成器の共通部分(CRTP)
lib/internal/internal_random.hpp -
ウェーブレット行列の共通コア(各 level のビットベクトル型を差し替え可能にする)
lib/internal/wavelet_matrix_base.hpp -
疑似乱数生成器 SplitMix64
lib/random/split_mix64.hpp -
疑似乱数生成器 xoroshiro128++
lib/random/xoroshiro128.hpp
検証プログラム(1)
-
test/yosupo/data_structure/point_set_range_frequency.test.cpp
test/yosupo/data_structure/point_set_range_frequency.test.cpp
実装
#pragma once
#include <vector>
#include "internal/dynamic_bit_vector.hpp"
#include "internal/wavelet_matrix_base.hpp"
/// @brief 要素の挿入・削除が可能な動的ウェーブレット行列
/// @complexity 構築は期待 $O(nL\log n)$、各操作は期待 $O(L\log n)$
template <class T, int L = 20>
struct DynamicWaveletMatrix : internal::WaveletMatrixCore<internal::dynamic_bit_vector, T, L> {
/// @brief 共通実装の基底型
/// @complexity 型エイリアスのため実行時コストなし
using Base = internal::WaveletMatrixCore<internal::dynamic_bit_vector, T, L>;
/// @brief 要素数を保持する基底クラスのメンバ
/// @complexity $O(1)$ で参照可能
using Base::length;
/// @brief 各レベルの動的ビットベクトルを保持する基底クラスのメンバ
/// @complexity 1 レベルの参照は $O(1)$
using Base::matrix;
/// @brief 各レベルの 0 の個数を保持する基底クラスのメンバ
/// @complexity 1 レベルの参照は $O(1)$
using Base::mid;
/// @brief 空の動的ウェーブレット行列を作る
/// @complexity $O(1)$
DynamicWaveletMatrix() = default;
/// @brief 列 `v` から動的ウェーブレット行列を構築する
/// @complexity 期待 $O(nL\log n)$
DynamicWaveletMatrix(std::vector<T> v) {
length = v.size();
std::vector<T> l(length), r(length);
for (int level = L - 1; level >= 0; --level) {
int left = 0, right = 0;
for (int i = 0; i < length; ++i) {
if (v[i] >> level & 1) {
matrix[level].insert(i, 1);
r[right++] = v[i];
} else {
matrix[level].insert(i, 0);
l[left++] = v[i];
}
}
mid[level] = left;
v.swap(l);
for (int i = 0; i < right; ++i) v[left + i] = r[i];
}
}
/// @brief 位置 `k` に値 `val` を挿入する
/// @complexity 期待 $O(L\log n)$
void insert(int k, T val) {
for (int level = L - 1; level >= 0; --level) {
const bool f = val >> level & 1;
matrix[level].insert(k, f);
k = matrix[level].rank(f, k);
if (f) k += mid[level];
else ++mid[level];
}
}
/// @brief 位置 `k` の要素を削除する
/// @complexity 期待 $O(L\log n)$
void erase(int k) {
for (int level = L - 1; level >= 0; --level) {
bool f = matrix[level][k];
int p = matrix[level].rank(f, k);
matrix[level].erase(k);
if (f) p += mid[level];
else --mid[level];
k = p;
}
}
/// @brief `k` 番目の値を返す
/// @complexity 期待 $O(L\log n)$
T access(int k) const { return Base::access(k); }
/// @brief `access(k)` の別名
/// @complexity 期待 $O(L\log n)$
T operator[](int k) const { return access(k); }
/// @brief $0 \le i < r$ かつ $v_i=x$ を満たす要素数を返す
/// @complexity 期待 $O(L\log n)$
int rank(int r, T x) const { return Base::rank(r, x); }
/// @brief $l \le i < r$ かつ $v_i=x$ を満たす要素数を返す
/// @complexity 期待 $O(L\log n)$
int rank(int l, int r, T x) const { return Base::rank(l, r, x); }
/// @brief 区間 $[l,r)$ 内で `k` 番目に小さい値を返す(0-indexed)
/// @complexity 期待 $O(L\log n)$
T kth_smallest(int l, int r, int k) const { return Base::kth_smallest(l, r, k); }
/// @brief 区間 $[l,r)$ 内で `k` 番目に大きい値を返す(0-indexed)
/// @complexity 期待 $O(L\log n)$
T kth_largest(int l, int r, int k) const { return Base::kth_largest(l, r, k); }
/// @brief 区間 $[l,r)$ にある `upper` 未満の要素数を返す
/// @complexity 期待 $O(L\log n)$
int range_freq(int l, int r, T upper) const { return Base::range_freq(l, r, upper); }
/// @brief 区間 $[l,r)$ にある $[lower,upper)$ 内の要素数を返す
/// @complexity 期待 $O(L\log n)$
int range_freq(int l, int r, T lower, T upper) const { return Base::range_freq(l, r, lower, upper); }
/// @brief 区間 $[l,r)$ にある `upper` 未満の最大値を返す
/// @details 該当する値がなければ `T(-1)` を返す。
/// @complexity 期待 $O(L\log n)$
T prev_value(int l, int r, T upper) const { return Base::prev_value(l, r, upper); }
/// @brief 区間 $[l,r)$ にある `lower` 以上の最小値を返す
/// @details 該当する値がなければ `T(-1)` を返す。
/// @complexity 期待 $O(L\log n)$
T next_value(int l, int r, T lower) const { return Base::next_value(l, r, lower); }
};