差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン次のリビジョン両方とも次のリビジョン | ||
programming_algorithm:data_structure:sparse_table [2019/12/05] – ikatakos | programming_algorithm:data_structure:sparse_table [2019/12/05] – [±1-RmQ] ikatakos | ||
---|---|---|---|
行 94: | 行 94: | ||
A={A0,A1,...,AN−1} の要素が、必ず「左の値から1増えるか1減るかのどちらか」で変化していく配列の最小値/ | A={A0,A1,...,AN−1} の要素が、必ず「左の値から1増えるか1減るかのどちらか」で変化していく配列の最小値/ | ||
- | この場合、実装はちょっとややこしくなるが、事前計算量と空間を O(NlogN) から O(N) に落とすことができる。 | + | この場合、実装はちょっとややこしくなるが、クエリ応答は O(1) のまま、事前計算量と空間を O(NlogN) から O(N) に落とすことができる。 |
なかなか特殊な条件に見えるが、木の最小共通祖先だったり、たまに使える。 | なかなか特殊な条件に見えるが、木の最小共通祖先だったり、たまに使える。 | ||
行 108: | 行 108: | ||
* ブロックを1要素として、SparseTableを構築する | * ブロックを1要素として、SparseTableを構築する | ||
* クエリに対して、完全に覆われるブロック内の最小値はSparseTableで求められる | * クエリに対して、完全に覆われるブロック内の最小値はSparseTableで求められる | ||
- | * はみ出る部分は個別に計算するが、変化パターンが+1か-1のみなので、どのパターンが事前計算して持っておいても大したサイズにならない | + | * はみ出る部分は個別に計算するが、変化パターンが限られるので、事前計算して持っておいても大したサイズにならない |
| | ||
行 124: | 行 124: | ||
ブロック内の変化は、今回1ブロック3要素なので、%%「++」「+-」「-+」「--」%%の4通りしかない。 | ブロック内の変化は、今回1ブロック3要素なので、%%「++」「+-」「-+」「--」%%の4通りしかない。 | ||
- | ブロック内での、各パターンの区間 [l,r] の最小値配列は、事前計算で作っておいても間に合う容量である。(ブロックサイズを s とすると s22s−1) | + | なので、全変化パターン・全区間 [l,r] の最小値配列を事前計算で作っても、現実的な容量で間に合う。 |
+ | ブロックサイズを s とすると s22s−1 | ||
+ | |||
+ | 先頭要素が0だったとして、最小値を計算しておく。 | ||
[++] | [++] | ||
行 144: | 行 147: | ||
log2N2 が良いとされている。端数はどちらでもよいが、とりあえず切り上げとする。 | log2N2 が良いとされている。端数はどちらでもよいが、とりあえず切り上げとする。 | ||
- | というのも、こうするとブロックの個数は 2Nlog2N となる。 | + | こうするとSparseTable, |
+ | |||
+ | SparseTableの方は、ブロックの個数が 2Nlog2N となる。 | ||
この要素数でSparseTableを構築すると、2NlogNlog2NlogN=O(N) となる。 | この要素数でSparseTableを構築すると、2NlogNlog2NlogN=O(N) となる。 | ||
行 150: | 行 155: | ||
また、個別計算の方も、logN222logN2−1=O(log2N√N) となり、O(N) より小さくなる。 | また、個別計算の方も、logN222logN2−1=O(log2N√N) となり、O(N) より小さくなる。 | ||
+ | |||
+ | === 拡張性 === | ||
+ | |||
+ | 必ずしも±1で遷移する場合に限定しなくても、ブロック内全区間の事前計算テーブルのパターン数が 2s 程度で収まる場合、同じ理由で活用できそう。具体的にあるかは知らんけど。 | ||