CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!) - E. Monsters (2100)
내 풀이
Multi-source BFS + DSU + Small To Large로 풀었다.
$a_i=0$ 인 것들을 모두 큐에 넣고 만나게 되는 것들은 DSU에서 merge 해준다.
이 과정에서 현재 $u$에 있고 인접한 노드 $v$에 대해 $a_v$ 가 아직 현재 집합의 크기보다 커서 못가는 경우, $u$의 집합에 다음과 같이 pair
를 추가한다.
($a_v$, $v$)
이 집합도 DSU에서 각 노드마다 관리하며 Small to Large로 MLE나 TLE를 피한다.
이제 어떤 노드 $c$에 방문했을 때 pending 된 것 들 중 방문되지 않고 현재 집합의 크기보다 $a_i$ 가 이하인 것이 있다면 방문해준다.
집합을 다룰땐 iterator
를 쓰는 것보다 while
문으로 뭔가 작업을 해주는게 동시 변경 에러를 피하는 안전한 구현법이 되는 것 같다. Small to Large문제를 몇개 풀어보긴 해야겠다.
에디토리얼 풀이
$S(u)$를 $u$에서 시작해 도달할 수 있는 정점 집합이라고 하자.
정점 집합 $T$에 대해 $E(T)$를 $T$들 정점의 인접 리스트 정점 목록이라고 하자.
어떤 고정된 정점 $u$로부터 문제를 해결하기 위해 $S(u)$와 $E(S(u))$ 를 집합으로 관리한다.
처음에 $S(u)=u$ 이다. $v \in E(S(u))$ 인 $v$ 들 중 가장 작은 $a_v$ 를 가진 $v$ 를 살핀다.
만약 $a_v \le \vert S(u) \vert$ 라면 $v$를 $S(u)$에 추가할 수 있다. 같이 $E(S(u))$ 도 업데이트한다.
결국 우리의 목적은 어떤 $u$가 $\vert S(u) \vert=n$ 이 되게 하는 것이다.
Lemma - if $v \in S(u)$, then $S(v) \subseteq S(u)$
그렇지 않다면 위의 과정에서 $x \not\in S(u)$이고 인 $x$를 $S(v)$에 추가한다 하자.
이 때, $\vert S(v) \vert < \vert S(u) \vert$ 여야 한다.(이건 $S(u)$에 없는 정점을 추가한 처음 순간이기 때문에, 만약 $S(u)=S(v)$ 였다면 $x$는 무조건 $S(u)$에도 추가되므로 이 경우는 고려하지 않는다)
그럼 $x \in E(S(u))$ 여야 하고 $a_x > \vert S(u) \vert \ge \vert S(v) \vert$ 이기 때문에 모순이다.
따라서 우린 $x$를 $S(v)$에 추가할 수 없다.
따라서 $\vert S(u) \vert < n$ 이라면 $v \in S(u)$ 인 모든 $v$에 대해서 탐색할 필요가 없기 때문에 모든 $i$ 에 대해 방문되지 않은 상태일 때만 검사해줄 수 있다.
각 정점 $v$에 대해 만약 $v \in S(u)$라면 어떤 $u'$에서 알고리즘을 시작할 때 $v$는 $S(u')$에 또 포함될 수 있다.
그럼 $\vert S(u') \vert > 2\vert S(u) \vert$가 된다.
$u$ 에서 시작했을 때 방문되지 못한 정점 $x$가 $u'$ 에서 시작되었을 때 방문되었다면 $x$를 방문하기 전까지 $\vert S(u') \vert$가 $\vert S(u) \vert$보다 컸다는 것이므로 최소 두배보다 커야한다.
한번 방문될 때 집합의 크기가 두배 커지므로 한 정점은 최대 $O(\log n)$번 방문되고(실제로는 더 적게 방문될 것)
set
의 시간복잡도를 고려해 $O(n \log ^2n)$에 문제가 해결된다.
Comments