문제 링크
- http://icpc.me/22306
사용 알고리즘
- Small to Large
시간복잡도
- $O(N \log^2 N)$
풀이
Small to Large 연습 문제로 유명한 BOJ 17469 트리의 색깔과 쿼리의 온라인 버전입니다.
각 컴포넌트의 아이디를 관리하면서, 각 정점이 몇 번 컴포넌트에 속한 상태인지 관리합시다. 각 정점이 몇 번 컴포넌트에 속했는지 알고 있다면, std::map
등으로 컴포넌트의 색깔들을 관리할 수 있습니다.
간선이 끊어질 때마다 컴포넌트의 아이디를 갱신하는 작업이 문제인데, 분할되는 두 컴포넌트 중 작은 컴포넌트에 속한 정점들의 아이디만 바꿔주면 Small to Large의 원리로 정점의 아이디는 총 $O(N \log N)$번 바뀌게 됩니다. 실제로 각 컴포넌트의 크기를 직접 구하는 것은 어렵고, 두 컴포넌트에서 모두 DFS를 돌리면서 한쪽이 끝날 때까지만 탐색을 수행하면 됩니다. 아래 코드의 Divide
함수를 참고해주세요.
DFS를 하는데 걸리는 시간과 std::map
을 이용해 컴포넌트를 관리하는 것 모두 $O(N \log^2 N)$이 걸리므로 전체 시간 복잡도는 $O(N \log^2 N)$입니다.
Dynamic Tree(ex. Euler Tour Tree)를 이용해 컴포넌트의 크기를 amortized $O(\log N)$ 시간에 구하고, std::map
대신 hash table을 사용하면 $O(N \log N)$에 풀 수도 있습니다. 이 코드도 함께 첨부합니다.
전체 코드
1 |
|
$O(N \log N)$ with Euler Tour Tree
1 |
|