ARMERIA

Rubyと競技プログラミングの話 AtCoderやCodeforcesの問題解説記事が多め。

Codeforces Global Round 6 F. Almost Same Distance

Problem - F - Codeforces

問題概要

 n 頂点の木が与えられる。いくつかの頂点からなる集合  W が正整数  k に対して以下の条件を満たすとき、 W は almost  k-uniformであると呼ぶことにする。

  •  W に含まれる異なる2頂点のペア全てにおいて、その距離は  k または  k+1 である。

 k=1, ..., n それぞれに対して、almost  k-uniformである集合の最大サイズを求めよ。

制約

  •  2 \le n \le 5\times 10^{5}
  • 与えられるグラフは木である

解法

集合  W がalmost  k-uniformであることを、簡単のため「 W は条件  U(k) を満たす」と書くことにします。頂点  a の次数を  \deg(a) と表記します。頂点  a, b 間の距離を  D(a, b) と表記します。

特別ケースを処理

まずはいくつかの特別ケースを処理しておきます。

1頂点からなる集合は「異なる2頂点のペア」が存在しないため、自動的に任意の  k に対して  U(k) を満たします。

 k=1 の場合を特別に考えます。「ある1頂点とその隣接頂点全てからなる集合」およびその部分集合は必ず  U(1) を満たし、また  U(1) を満たす集合はこのようなものに限られます。そのため  k=1 に対する答えは、頂点の次数の最大値に1を足したものになります。

以降は  k \ge 2 に対して考え、2頂点以上からなる集合だけを考慮します。

頂点を基準に考えて作る集合

例えば「ある1つの頂点  r から見て、経路が重複せず等距離にあるような頂点の集合」を考えます。この距離が  d であるとき、集合内の異なる2頂点間の距離は全て  2d になります。

f:id:betrue12:20191218231931p:plain

このように、「ある頂点  r を根と見なし、 r のそれぞれの子が持つ部分木から高々1個ずつの頂点を選ぶ」という方法で作る集合について考えます。

実際には距離が  k または  k+1 であれば  U(k) を満たすので、 r からの距離が全て等しい必要はありません。具体的には以下の3パターンが考えられます。

  1.  r からの距離が  \lbrace d-1, d, ..., d \rbrace となるように頂点を選ぶ。このとき2頂点間の距離は  2d-1 または  2d なので、集合は  U(2d-1) を満たす。
  2.  r からの距離が全て  d となるように頂点を選ぶ。このとき2頂点間の距離は全て  2d なので、集合は  U(2d) を満たす。
  3.  r からの距離が  \lbrace d, ..., d, d+1\rbrace となるように頂点を選ぶ。このとき2頂点間の距離は  2d または  2d+1 なので、集合は  U(2d) を満たす。

このうちパターン3については考える必要がありません。 d+1 の頂点を1つ浅い頂点に置き換えることで、必ずパターン2に変換できるからです。

またこのようにして作った集合が  U(k) を満たすならば、頂点を適切に浅いものと置き換えることで、必ず同サイズで  U(k-1) を満たす集合を作ることができます。そのため使う頂点の個数を決めたら、なるべく大きい  k について  U(k) を満たすように頂点を選べば良いです。

ということで、 2 \le s \le \deg(r) であるそれぞれの  s について、 s 個の部分木から頂点を1つずつ選んでサイズ  s の集合を作ることを考えます。この集合が  U(k) を満たすような最大の  k は以下のように求めることができます。

  1.  r の子が持つ部分木それぞれについて、その部分木内で最も  r から遠い頂点との距離を計算する。
  2. 上記の距離を大きい方から  s 個取り、その最小値を  d_{\min} とする。
  3.  s 個の距離の中に  d_{\min} が1個だけ含まれる場合、最大で  U(2d_{\min} + 1) を満たすような集合が取れる。そうでない場合、最大で  U(2d_{\min}) を満たすような集合が取れる。

これは木DPで計算できます。各頂点  v について「 v の子が持つ部分木それぞれについての、その部分木内で最も  v から遠い頂点との距離を集めたもの」を  dp\lbrack v \rbrack とし、その最大値+1を順次親に渡していきます。根  r に情報が集まったら、 dp\lbrack r \rbrack を用いて上記の計算ができます。実際には  r を全通り試す必要がありますが、これは全方位木DPで処理することができます。

この集合の作り方で、各  k について求めた「 U(k) を満たす集合の最大サイズ」を  ans_{1}\lbrack k \rbrack とします。先ほど書いたように集合が  U(k) を満たすならば必ず同サイズで  U(k-1) を満たせるので、 r を全通り処理した後は  k が大きい順に「 ans_{1}\lbrack k \rbrack \max(ans_{1}\lbrack k \rbrack, ans_{1}\lbrack k+1 \rbrack) に置き換える」という処理をしてやれば良いです。

計算量については、 \deg(r) の総和が  O(n) なので、各  r に対して  s を1つずつ処理したとしても合計で  O(n) 通り。距離のソート等を考慮しても  O(n\log n) でできるので計算量は大丈夫です…今のところは。

辺を基準に考えて作る集合

実はこれまで考えたパターンだけでは考慮できないケースが存在します。以下の図のような場合です。

f:id:betrue12:20191219000249p:plain

これは「ある1本の辺を基準として、その両端の頂点  r, c が持つ部分木から、経路が重複せずに  r, c それぞれからの距離が全て等しく  d である頂点を選んだもの」です。この集合の2点間距離は  2d または  2d+1 になり、 U(2d) を満たします。これは先ほどのパターンでは考慮できないものです。

これも同じように全方位木DPで処理します。根  r とその子  c を繋ぐ辺を見る時には、先ほどの  dp\lbrack r \rbrack(から  c 以下の部分木に由来する値を除いたもの)と  dp\lbrack c \rbrack を使います。これらの距離を混ぜて大きい方から  s 個取り、その最小値を  d_{\min} とすれば、 U(2d_{\min}) を満たすサイズ  s の集合を構成できます。

またこのようにして作った  U(2d) を満たす集合からは、全ての頂点を1つ浅いものに入れ替えることで U(2d-2) を満たす集合を作ることができます。 U(2d-1) を満たす集合にはできません。

これで先ほどと同じように解けたように見えますが、問題は計算量です。各  r, c のペアについてサイズ  s を1つずつ試すと、次数について2乗オーダーの計算量が掛かるので間に合いません。

計算量削減のため、 dp\lbrack v \rbrack として個々の値を単純に並べるのではなく、「値○が△個」という形にした頻度表で持つことを考えます。 dp\lbrack r \rbrack dp\lbrack c \rbrack を混ぜた時、そこに含まれる距離を合計した値は  O(n) です。つまりその種類数は  O(\sqrt{n}) になります。

集合のサイズとして  s の値を全て試す必要はなく、以下のように各種類ごとにまとめて処理することで、1本の辺についての処理が  O(\sqrt{n}) で完了し、全体  O(n\sqrt{n}) で計算することができます。

f:id:betrue12:20191219005020p:plain

この集合の作り方で、各  k について求めた「 U(k) を満たす集合の最大サイズ」を  ans_{2}\lbrack k \rbrack とします。先ほど書いたように集合が  U(k) を満たすならば必ず同サイズで  U(k-2) を満たせるので、 r を全通り処理した後は  k が大きい順に「 ans_{2}\lbrack k \rbrack \max(ans_{2}\lbrack k \rbrack, ans_{2}\lbrack k+2 \rbrack) に置き換える」という処理をしてやれば良いです。

まとめ

こうして「頂点を基準に考えて作る集合」と「辺を基準に考えて作る集合」、そして冒頭に書いたいくつかの特別ケースを考えてきました。これで考えるべきパターンが尽くされているため、 k ごとにそれぞれで求めた集合サイズの最大値を取ることで答えが求められます。

考えるべきパターンがこれで尽くされていることの証明

Editorialには書いていなかったので証明を付けておきます(がんばりました)。

これまでの説明ではパターンを天下り的に列挙してきましたが、考えるべき集合  W がこれらのパターンで尽くされていることを確認する必要があります。「特別ケース」として扱った  k=1 の場合とサイズ1の集合については良いとして、 k \ge 2 に対して  U(k) を満たすサイズ2以上の集合  W が、先に説明した「頂点基準」あるいは「辺基準」の作り方で作られる集合のいずれかに合致することを示します。

まず  k \ge 2 を仮定すると、 W に含まれる3頂点以上が1本のパスに含まれることはありません。この3頂点を並んだ順に  a, b, c とすると、 D(a, c) = D(a, b) + D(b, c) \ge D(a, b) + 2 となり条件を満たさないからです。

 W に含まれる2頂点間のパス全ての和集合である辺の集合  E(W) を取ります。この集合において「枝分かれ」、つまり  E(W) に含まれる辺が3本以上繋がっている頂点がいくつあるかで場合分けします。

枝分かれが0個の場合

 E(W) そのものがパス、つまり  W のサイズが2である場合です。これは「頂点基準」で作られる集合に含まれます。

枝分かれが1個の場合

この枝分かれになっている頂点を  r とすると、これは「頂点基準」での集合の作り方そのものです。そして  U(k) を満たすためには、 r から  W の各要素までの距離について

  • 最大値と最小値の差が2以上あってはいけない
  • 複数個含まれる値が2種類以上あってはいけない

ことが分かるので、これらの距離は先に列挙したパターンのいずれかに合致します。

枝分かれが2個の場合

枝分かれになっている頂点を  r, c とすると、 W には以下のような関係にある4頂点  p, q, a, b が含まれます。図中の距離  P, Q, A, B, Z は全て正です。

f:id:betrue12:20191219204850p:plain

この図において、 U(k) の条件より以下が両方成り立つ必要があります。

  •  |D(p, q) - D(p, b)| = |Q - B - Z| \le 1
  •  |D(a, q) - D(a, b)| = |Q - B + Z| \le 1

この条件から  Z = 1 であること、そして  Q = B であることが求められます。これと同様の数式を頂点を並び替えて立てることで、 P = Q = A = B を証明することができます。

つまり W が条件  U(k) を満たし、 E(W) の枝分かれが2個でなる場合は、 W は「辺基準」の作り方で作られる集合の条件に合致します。

枝分かれが3個以上の場合

 E(W) において枝分かれが3個以上ある場合には、 W が条件  U(k) を満たしていることはあり得ません。

枝分かれが3個以上あるとき、必ず距離が2以上離れた2つの枝分かれ頂点が存在します。つまり先ほどの図と同じ位置関係にある頂点において、 Z \ge 2 であるようなものが存在するということです。これでは必ず条件  U(k) を満たせません。

以上で  W としてあり得る全ての場合が考慮され、列挙したパターンで十分であることが示されました。

ACコード

Submission #67114277 - Codeforces