Ex - Range Harvest Query Editorial by ygussany


kyopro_friends さんの解説にあるように座標圧縮+遅延セグメント木でも解けますが,圧縮後の座標を平方分割することでも容易に AC を得ることができます.

\(R_i\)\(1\) を足すことにして,各クエリ区間を半開区間 \([L_i, R_i)\) として扱います.\(L_i, R_i\) \((i = 1, 2, \dots, Q)\)\(1, N + 1\) と併せて座標圧縮します.\(N + 1\)\(n + 1\) に圧縮されたとして,\(j = 1, 2, \dots, n + 1\) に圧縮された元の座標を \(x_j\) とします.このとき,各 \(j = 1, 2, \dots, n\) は元の半開区間 \(I_j = [x_j, x_{j+1})\) に対応するとも見なせ,収穫範囲はいくつかの \(I_j\) の和集合で表せるので,対応する \(j\) の区間を収穫範囲と見なすことにします.

\(j\) について,半開区間 \(I_j\) 内の整数の総和は \(S_j = \displaystyle\frac{(x_j + x_{j+1} - 1)(x_{j+1} - x_j)}{2}\) であり,\(j\) が収穫範囲に含まれる場合には,\(j\)最後に収穫されてから経過した日数\(S_j\) を掛けたものを答えに足せばよいです. すべての \(j\) について最後に収穫された日を素朴に管理しておけば,各クエリに \(\mathrm{O}(n)\) 時間で答えることが可能ですが,\(n\) は最大で \(2Q + 1\) になるので実行時間制限に間に合う保証はありません.

そこで,圧縮後の全区間 \([1, n + 1)\)\(\sqrt{n}\) 個程度の長さ \(\sqrt{n}\) 程度のブロックに分割し,それぞれのブロックについて,ブロック内の \(S_j\) の総和と,

  • 最後に収穫された日がブロック内ですべて同じ
  • そうではない

のいずれであるかを管理し,前者であればその日を記憶しておきます. これにより,前者に該当するブロック内を丸ごと収穫する部分の計算量は \(\Theta(\sqrt{n})\) から \(\Theta(1)\) に落とせます. また,各クエリについて後者のブロックは高々 \(2\) 個(両端)しか増えず,後者のブロック内を丸ごと収穫するクエリが来ればそのブロックは前者に移行するため,ブロック内を愚直に計算しなければならない回数は全体を通して \(\mathrm{O}(Q)\) 回で抑えられます.

以上より,全体の計算量は \(\mathrm{O}(Q\sqrt{Q})\) となり,実行時間制限に十分間に合います.

実装例 (C, 1081 ms)

posted:
last update: