Official

Ex - Beautiful Subsequences Editorial by nok0


\(K=0\) の場合

\(K=0\) の場合、以下の手法でこの問題に答えることができます。

遅延セグ木の \(L\) 番目の要素で、\((\mathrm{max}(P_L,\ldots,P_R) - \mathrm{min}(P_L,\ldots,P_R)) - (R -L )\) を管理します。

実はこの管理は区間加算のみを使って可能なので、区間加算 - 区間最小値とその個数の取得 を行う遅延セグ木を用い、 \(R\)\(1,\ldots,N\) と動かすことによりこの問題に答えることができます。

遅延セグ木の更新方法

\(-(R-L)\) の部分は容易なので、以下では \(\mathrm{max}(P_L,\ldots,P_R)\) の部分をどのように区間加算によって管理するかを述べます。

ここで、stack を用いて最大値を管理するテクニックを応用することを考えます。


Stack で最大値を管理するテクニック

ある \(R\) を取ってきたとき、 \(\mathrm{max}(A_i, A_{i+1},\ldots,A_R)\)\(i\) について単調非増加になっています。

\(R\)\(1,2,\ldots,N\) と順に増加していくとき、 \(\mathrm{max}(A_i, A_{i+1},\ldots,A_R) \neq \mathrm{max}(A_{i+1}, A_{i+2},\ldots,A_R)\) なる \(i\) は、以下の手法を用いることにより stack で管理することができます。

  • 空の stack を用意する。
  • R が 増加するたびに、以下を行う。
    • stack が空でなく、stack の 先頭の値が \(A_R\) 未満である限り stack の先頭を pop する。
    • \(A_R\) を stack に push する。

\(A_1,A_2,\ldots,A_N\) はそれぞれ最大 \(1\) 回しか push されないので、このアルゴリズムは \(\mathrm{Ο}(N)\) で動作します。


上記の手法を用いることにより、この区間の最大値は \(X\) であるという情報が得られるので、区間加算で最大値を管理できます。(pop した場合、加算していた区間を取り消すように区間加算を行えばよいです。)

\(\mathrm{min}\) についても同様の手法で可能です。

計算量は \(\mathrm{O}(N\log N)\) です。

一般の場合

一般の場合も、遅延セグ木を少し変更すればよいです。最小値と個数を管理するのではなく、小さい値とその個数を順に \(K+1\) 個管理すれば良いです。

計算量は \(\mathrm{O}(NK\log N)\) もしくは\(\mathrm{O}(NK^2\log N)\)です。

補足(追記)

この問題は、 Permutation Tree と呼ばれるデータ構造の構築アルゴリズムを一部切り出したものです。 興味のある方は Permutation Tree についても調べてみてください。

文献

posted:
last update: