ARC 098 E - Range Minimum Queries
数列A1,A2,...を昇順に並べ替えたものをA1′≤A2′≤...とする。最大値-最小値をすべて試すなら、だいたい次のようになるはずだ。
- 数列(Ai)の小さいほうからQ個取り除いて最大値-最小値を求める。
- A1′を残したままにしつつ(Ai)からできるだけ小さい数を取り除いてゆき、Q個取り除けたら最大値-最小値を求める。
- A1′,A2′を残したままにしつつ(Ai)からできるだけ小さい数を取り除いてゆき、Q個取り除けたら最大値-最小値を求める。
- …
これは高々O(N)ステップで済むので、ひとつひとつのステップがO(N)かO(NlogN)くらいで実行できればよい。
小さい数を取り除いていく具体的な手順を与えるために、上のステップ3について考えてみる。A1′=Ap,A2′=Aqとする。
A1,A2,...,Ap−1 ∣ Ap+1,Ap+2,...,Aq−1 ∣ Aq+1,Aq+2,...,AN
Ap, Aqを残したまま数を取り除いていくというのは、上の数列の縦線をまたがないように連続したK個を選んで、その最小値を除いていくということにほかならない。なぜならAp,Aqはほかの数より小さいので、縦線をまたぐとAp,Aqが取り除かれてしまうからだ。つまり、(Ai)を複数の独立した数列に分割してそれぞれの最小値を見ればよさそうだ。
さて、「複数の独立した数列」をどう管理すればよいかが問題である。上の3つの部分列をA1,A2,A3とする。これらの数列から小さい数を除いていくとき、数列の最小値と長さにしか興味がないので、A1,A2,A3はそれぞれ(昇順の)優先度付きキューで表すことができる。さらに、A1,A2,A3自身も優先度付きキューQにいれることにし、Qの順序はA≤A′:⇔ Aの最小値≤A′の最小値 とする。
一般に、l個の部分列からQ個の数を取り除く操作を書き下すと、次のようになる。
- A1,A2,...,Alの中で長さがK以上であるものだけQに入れて、残りは捨てる。
- 次のステップを最大Q回繰り返す。
- Qの先頭から数列Aを取り出す。
- Aの最小値を取り出す。
- Aの長さがまだK以上ならQに戻し、K未満なら捨てる。
- Qが空になる前にQ個の数を取り出せたなら、その最大値-最小値を求める。
以上で答えが求まる。全体の計算量はO(N2logN)。
問題を読んだときはNが小さいので何をやってもできそうな気がしたけど、具体的な手順を与えるのに膨大な時間をかけてしまった。