Crate nekolib_doc::discussion::decomposable
source · Expand description
分解可能なクエリ。
§Preliminaries
集合 $S\subseteq U
$ と要素 $x\in U
$ に関する問題 $Q_S(x)
$ を考える。
$S\cup T
$ に対する問題を解くにあたって、何らかの二項演算 $\square
$ が存在して
Q_{S\cup T}(x) = Q_S(x) \mathop{\square} Q_T(x)
と書けるとき、問題 $Q
$ は decomposable であるという。
§Theorems
二種類のクエリを考える。
- $
x
$ が与えられ、$S \xgets{\cup} \{x\}
$ で更新する。 - $
x
$ が与えられ、$Q_S(x)
$ を出力する。
$Q_S(x)
$ が $\angled{f(|S|), g(|S|)}
$ 時間で解けるとき、$n
$ 個のクエリを $O((f(n) + n\cdot g(n))\log(n))
$
時間でオンライン処理できる。
ただし、$f(n)\in n^{\Omega(1)}
$, $g(n)\in n^{o(1)}
$ とし、$\square
$ の計算も $O(g(n))
$ 時間でできるとする。
たとえば、$Q_S(x)
$ が $\angled{O(|S|\log(|S|)), O(\log(|S|))}
$ 時間で解けるなら、$n
$ 個のクエリを $O(n\log(n)^2)
$ 時間で処理できる。
§Ideas
$i
$ 番目の更新クエリの値を $x_i
$ として、次のようなセグ木をイメージする。
- $
i
$ 番目の葉に $\{x_i\}
$ を持つ。 - 子が $
S_L
$, $S_R
$ を持っている頂点は $S_L\cup S_R
$ を持つ。 - $
S
$ を持つ頂点では $Q_S
$ のためのデータ構造を保持する。
更新クエリを $k
$ 個処理している状態では、$[0\lldot k)
$ をカバーする区間にあるデータ構造を用いて各々を処理し、$\square
$ で合成する。
実際にはこのセグ木の各ノードは更新せず、また各ノードを陽に持っておく必要もない。
次の擬似コードに示すようにして、高々 $\log_2(n)
$ 個のデータ構造を保持しておけばよい。
meld
の際には、other
の各要素を直接 self
に追加してもよいし、一旦 .into_iter()
のようなことをしてから再構築してもよい。
enum Query<T> {
Union(T),
Search(T),
}
use Query::*;
let qs = Vec::<Query<()>>::new();
struct Ds<T> {
// ...
}
impl<T> Ds<T> {
pub fn singleton(elt: T) -> Self {
// ...
}
pub fn search<U>(&self, elt: &T) -> U {
// ...
}
pub fn meld(&mut self, other: Self) {
// ...
}
}
let mut clx = vec![];
let mut count = 0_usize;
for q in qs {
match q {
Union(x) => {
count += 1;
clx.push(Ds::singleton(x));
for _ in 0..count.trailing_zeros() {
let tmp = clx.pop().unwrap();
clx.last_mut().unwrap().meld(tmp);
}
}
Search(x) => {
let _ = clx.iter().map(|si| si.search(&x)).fold(id, compose);
}
}
}