Processing math: 100%
본문으로 바로가기

Centroid에 관하여

category Problem Solving 5년 전

Centroid는 트리의 중심을 의미한다.

 

모든 이웃의 서브트리의 크기가 전체 트리 크기의 절반 이하가 되도록 하는 정점을 의미한다.

 

그렇기 때문에 용도가 재귀적이다.

 

트리에서 O(N)이나 O(NlogN) 수준에서 문제의 조건을 만족하는 단 하나의 경로를 찾아야하는 문제에 대해서는 무조건 센트로이드를 떠올려야 한다.

 

 

센트로이드의 정의를 이용한 예제

https://codeforces.com/contest/1205/problem/D

 

Problem - D - Codeforces

 

codeforces.com

좋은 수학문제다. 센트로이드를 중심으로 이웃 노드를 2개의 파티션으로 분할하여 서브트리의 크기 합이 각각 N/32N/3 사이에 오도록 만들 수 있다. 각각의 수를 ab라고 하면, 첫 번째 파티션에는 센트로이드에서 거리가 1,2,3,,a 인 경로가 생기도록 간선에 가중치를 주고. 두 번째 파티션에는 a+1,2(a+1),3(a+1),,b(a+1) 까지 만든다. 그러면 센트로이드를 통해 갈 수 있는 거리가 1부터 (a+1)(b+1)1 까지 인 경로들이 모두 존재한다.

 

 

..한 최대 경로 구하기 O(N2) 미만으로 푸는 예제

모든 경로에 대해 ..한 값을 구하시오. 같은 문제는 어렵다. 모든 경로를 탐색하는데 걸리는 시간이 O(N2) 이기 때문이다.

 

하지만 센트로이드를 루트로 생각해서, 루트를 중간에 경유하는 경로 중 최대값을 구한다면 꽤 간단해지는 경우가 있다. 이후 센트로이드를 없는 정점으로 간주하고 남은 서브트리들에 관해 작업을 해주면 된다. 시간복잡도가 아래로 볼록한 함수들이라면 젠센 부등식에의해 O(logN) 정도 오버헤드만 붙어 빠르게 처리된다는 것을 알 수 있다.

 

보통 이런 경우 루트로 올라가는 경로에 대한 정보(ToR), 루트로부터 내려가는 경로에 대한 정보(FromR)을 저장한 후, ToR[x]와 FromR[y] 정보를 혼합하여 정점 x에서 y로 루트를 경유해서 가는 경로를 처리한다.

 

 

https://www.acmicpc.net/problem/15539

 

15539번: Non-redundant Drive

The people of JAG kingdom hate redundancy. For example, the N cities in JAG kingdom are connected with just N − 1 bidirectional roads such that any city is reachable from any city through some roads. Under the condition, the number of paths from a city to

www.acmicpc.net

이제 Well-known이 될만한 유형의 문제이다.

 

센트로이드를 r이라고 하자. (루트다.)

정점 a에서 r로 가는 경로를 a=a1,a2,,ak=r, r에서 b로 가는 경로를 r=b1,b2,,bt=b 이라고 하자. a에서 r로 갈 수 있을 조건은 모든 i에 대해 a1da1,a2+a2da2,a3++aidai,ai+10 을 만족하는 것이다. r에서 b로 가는 경우도 비슷하게 정의된다. To Root에 대한 정보가 주어질 때, 루트에서 남은 연료로 갈 수 있는 최대 높이를 이분탐색으로 찾는다. 각 센트로이드에 대해 O(NlogN)이 걸리므로 전체 시간은 O(Nlog2N) 이다.

 

단순 경로에 대한 부분을 처리하는 부분이 까다롭다. 센트로이드의 이웃 노드를 s1,s2,,sp라고 하자. 다음 두 작업을 통해서 이 문제를 해결할 수 있다.

  • i=1,2,,p 순서대로 루프를 돈다. si의 서브트리의 모든 노드에서 루트로 가는 경로에 대한 부분을 처리한다. 이후 루트에서 si의 서브트리의 모든 노드로 가는 경로를 처리한다. 즉 To Root 정보를 먼저, From Root 정보를 나중에 처리한다. 이렇게 루프를 돌면 x>y를 만족하는 sx의 서브트리의 임의의 노드에서 sy의 서브트리의 임의의 노드로 가는 단순 경로에 대한 내용이 처리된다.
  • i=p,p1,,2,1 순서대로 루프를 돈다. 마찬가지로 si의 서브트리의 모든 노드에서 루트로 가는 경로에 대한 부분을 처리한다. 이후 루트에서 si의 서브트리의 모든 노드로 가는 경로를 처리한다. 이렇게 돌면 x<y를 만족하는 sx의 서브트리의 임의의 노드에서 sy의 서브트리의 임의의 노드로 가는 단순 경로에 대한 내용이 처리한다.

사실 나는 From Root 정보에서 높이 당 max 값을 2개씩 저장하는 방식으로 처리하긴 했다. 어느 방식이든 좋은 아이디어인 것 같은데, 루프 두 번을 도는 방식이 조금 더 범용적으로 쓰이는 것 같다.

 

 

https://codeforces.com/contest/1303/problem/G

 

Problem - G - Codeforces

 

codeforces.com

비슷한 문제다. 그런데 센트로이드 최대 경로 + 컨벡스헐 트릭이라는 짬뽕 유형이라 볼 수 있다. 그래도 센트로이드 문제구나! 하는거 빠르게 캐치한 후 성실하게 식 세우고 코드짜면 맞출 수 있는 효자 문제다.

 

Non-redundant Drive 문제와 마찬가지로 i를 올라가고 내려가고 하는 루프로 슥슥 갱신해주면 된다. 다만 그 과정에서 컨벡스헐 트릭을 써야하므로 Li Chao 트리를 만들어 From Root에 대한 내용물을 첨가해주면 된다. Li Chao 트리를 초기화할 일이 많은데, 다이나믹 세그먼트 트리를 다 비울 필요 없이 그냥 left, right 자식들을 끊어주기만 하면 된다.

 

캐시 최적화를 안 시켜서 한 13번 정도 TLE를 받았다.. From Root, To Root에 대한 정보를 굳이 배열에 저장하지 않고 DFS를 돌면서 처리하는게 훨씬 random access를 덜 해서 빠르게 돌아가는 것 같다. 한 8배 빠르게 돌아갔다. 큰 교훈을 얻었던 여러모로 좋은 문제이다.

 

 

https://www.acmicpc.net/problem/13854

 

13854번: 트리와 소수

서로 다른 두 개의 정점을 균일한 확률로 랜덤하게 선택했을 때, 거리가 소수일 확률을 출력한다. 절대/상대 오차는 10-6까지 허용한다.

www.acmicpc.net

딱 이 유형 문제. 소수를 미리 에라토스테네스 체로 p1,p2,p3, 다 구해놓는다. 전체 count 변수에 icnt[pid]를 재귀적으로 더해주면 된다. N이 더 크다면 센트로이드+FFT 라는 좀 이상한 문제가 되겠지만.. 다행히 소수의 개수는 얼마 되지 않는다.

 

 

더 찾으면 추가해야지~~