G - Odd Position Sum Query Editorial
by
harurun4635
(クエリに対しての)平方分割
(問題文内でソート済み配列に \(B\) が用いられているため、ブロックサイズを \(D\) とします)
\(D\) クエリごとに以下を計算します。
・そのクエリまでに追加された要素のソート済み配列 \(B\)
・\(B\) の奇数項目のみの累積和
・\(B\) の偶数項目のみの累積和
各クエリでは、(ブロックごとに前計算した) \(B\) の配列に、高々 \(D\) 個の要素を挿入した時の問題を解けばよいです。
これは \(D\) 個の要素が \(B\) のどの位置に入るかを二分探索することで、累積和と合わせて解くことができます。
計算量は ブロックごとの更新が \( O( \displaystyle \frac{Q}{D} \cdot Q \log{Q})\)
クエリごとが \(O(Q \cdot (\log{Q} + D))\) などで解くことができ、\(D\) を\(\sqrt{Q \log{Q}}\) 程度にとることで、問題全体として \(O(Q \cdot (\sqrt{Q\log{Q}} + \log{Q}) )\) で解くことができます。
Python等の低速な言語であっても、実装に気を使えば十分に通ります。
実装例 (PyPy3)
(このコードでは \(D = \sqrt{Q}\) となっています。\(D = \sqrt{Q\log{Q}}\)のほうが、良いオーダーですが、実際にはTLEをしました)
クエリごとの計算量について
「挿入する要素」への追加・整列が \(O(D \log{D})\)
各「挿入する要素」について挿入位置の二分探索を行うのが \(O(D \log{Q})\)
実際に累積和を用いて計算するのが \(O(D)\)
1クエリ \(O(D\log{D} + D \log{Q})\) がわかりやすい実装方針としてあります。
しかし、この二分探索は、同じブロック内であれば \(B\) が変化しないため、1回で十分であるので、1クエリあたり \( O(\log{Q}) \) にできます。
「挿入する要素」への追加・整列も、挿入位置を二分探索してから \(\text{insert}\) をしたり、平衡二分木などを使ったりすることで \(O(\log{D})\) で可能です。
この改善を行えば上記の計算量になります。
posted:
last update:
