Senの競技プログラミング備忘録

こけた問題を自分用の解説で載せる。けんちょんさんのブログを目指したい。質的にも量的にも。こけた問題だけに限定するけど

第二回全国統一プログラミング王決定戦予選-D Shortest Path on a Line

atcoder.jp

概要

最大10^5個の頂点(それぞれ1~Nまで番号を振る)を持つ辺に次の最大10万個のqueryで無向辺を追加する。

クエリ
LとRとCを与えられる。 L <= a < b <= Rを満たすすべての(a, b)の間にコストCの辺を張る。

クエリを全部処理したのち、頂点1から頂点Nまでの最短経路問題を解け。

ACするまで

1. みんな通してるなぁー。制約的にDAGっぽい?->嘘でした
2. 愚直に辺を張ると辺の数が O(N^3)になる。すぬけ君の地下鉄旅行ターミナル駅を作る手法をしてもなお O(N^2)となり険しい。
3. データ構造でうまくやれないかなーと考える。->非想定解法でデータ構造で殴れます。(後程この記事に加筆)


4. 解説を参照。 [L, R]間ですべてに辺を張ることを、天才的な言い換えをすることで辺の数を O(N)にすることができる。2で述べた手法とは違い、これはほかのqueryでも再利用できる辺の貼り方をしてる。
5. AC

考察

この問題のキモはいかにして条件を保ったまま辺の数を減らすかである。もともとは O(N^3)であるが、どうにかして最終的には O(N)にしないといけない。

ターミナル駅を作る手法の詳細はこちらの記事を見てください。

ターミナル駅をつくる手法は O(N^2)に辺の数を落とせるが、それ以上の抜本的な改善は難しい(はず)

解説解法

ここで、解説の紹介してた辺の貼り方を説明する。

補題  d_1 <= d_2 <= ... <= d_nが成り立つ。

ひとまず、頂点1から離れれば離れるほど距離が遠くなることを証明する。(感覚ではそうなるけど)

 d_i > d_{i+1}が成り立つと仮定する。
適切な頂点 t から距離cの辺をたどって、頂点 i+1 に行きつくのが最短距離であるので、 d_{i+1}=d_t+cと、辺のコストcを使って書ける。
ここで、 i > tであるとき、同様に d_i = d_t+cと書けるが、これは仮定と矛盾する。
 i = tの時、 d_{i+1}=d_i+cと式はなるが、これも家庭と矛盾する。
よって、これをすべての iに適用させれば、距離は頂点1から離れるごとに広義単調増加することを示せた。

このことから、ひとまずすべての頂点 i+1 から頂点 i へコスト0の有向辺を張っても答えに影響はないことがわかる。

そして、 [L, R]への更新だが、頂点 L から頂点 R にコスト c の有向辺を張る。

こうすることで、 L <= a < b <= Rを満たす頂点 a から頂点 b へと行く方法は

  • a -> a-1 のコスト0有向辺で L にたどりつく。
  • L -> R へとコストcの有向辺でいく。
  • Rから a -> a - 1 のコスト0の有向辺で b にたどりつく。

である。

このようは天才的な張り方をすることで、

  • 前処理で a -> a - 1 へのコスト0の有向辺の計 O(N)本。(ターミナル方式と違いこちらはクエリごとに貼りなおさなくてもよい)
  • queryごとに L -> R へのコストCの有向辺の計 O(M)

の辺に抑えることができる。あとはこれでダイクストラすればよい。

ACコード:
Submission #8371381 - NIKKEI Programming Contest 2019-2