국제 옥토끼 기구
BOJ 17348
https://www.acmicpc.net/problem/17348
풀이 1 ()
Centroid decomposition을 이용한다.
각 센트로이드 에 대해서 가 담당하는 부분 트리의 각 정점 에 대해 를 모아서 정점 번호 기준으로 세그먼트 트리를 만들 수 있다.
쿼리로 받은 정점 에서 부모 센트로이드로 올라가면서 아직 처리되지 않은 정점들 중에 구간에 속하는 정점의 값을 계속해서 더해주어 답을 구할 수 있다. 이때 현재 처리된 정점들은 현재 센트로이드를 기준으로 했을 때 가 속하는 서브트리의 정점들이고, 이 서브트리들의 정점을 제외하고 계산할 수 있는 세그먼트 트리를 만들면 된다. 쿼리의 답을 구하는 과정을 아래의 pseudo-code와 같이 구현할 수 있다.
result query(int L, int R, int V) {
result ret;
for (int centroid = V; valid(centroid); centroid = parent_centroid(child_centroid = centroid)) {
ret.apply(segment_tree(centroid).get(left = L, right = R,
except_subtree_index = subtree_index(centroid = centroid, vertex = V)) + distance(V, centroid));
}
return ret;
}
트리를 전처리하는 시간복잡도는 이고, 각 쿼리의 시간복잡도는 이다.
풀이 2 ()
구간을 세그먼트 트리의 노드처럼 형태의 구간 개로 나눌 수 있다. 이때 이다. 이렇게 나누면 각 쿼리 를 와 같이 개의 쿼리로 분할할 수 있다. 이제 각 구간 에 대해 정점 와 의 거리를 구하는 쿼리를 수행하면 된다. 이러한 쿼리의 개수는 개가 된다.
어떤 구간 에 대해 쿼리 가 존재할 것이다. 정점 와 를 모두 모은 후 트리 압축을 하면, 의 시간복잡도에 DFS로 모든 답을 구할 수 있다. 트리 압축을 하는 과정에서 DFS order로 정렬을 해야 하는데, 모든 구간 에 대해서 정렬해야 하는 수들을 모은 후 카운팅 정렬을 하면 의 시간복잡도로 트리 압축을 모두 실행할 수 있다. 마지막으로 DFS를 통해 답을 구하는 과정은 이 되며, 총 의 시간복잡도로 문제를 해결할 수 있다.