B. 트리와 XOR
내가 트리에 좀 약하다는 걸 알고 있기 때문에 도전해봤다.
문제는 어떤 트리가 주어진다. 각각의 노드 vi에는 정수 ai가 적혀있다.
모든 ai를 같게 만들어야 한다.
이때 한 점에 대해서 연산 [vi,c]를 시행하면 vi를 루트로 하는 서브트리에 대한 모든 정점 j에 대해 aj를 aj⊕c로 변경한다. ⊕는 bitwise XOR을 의미한다.
이때의 비용은 s⋅c이다.
r번 정점이 트리의 루트일 때 목표를 달성하기 위한 최소 비용을 mr이라 할 때, m1,m2,…,mn을 구하는 문제이다.
풀이에 앞서
- 정수 A와 B가 있을 때, B⊕c가 A가 되게 하는 c는 A⊕B이다.
- A와 B가 서로 다른 정수라면 A⊕c와 B⊕c또한 서로 다른 정수이다.
- 그리고 그 둘을 bitwise XOR한 값은 동일하다. (A⊕c)⊕(B⊕c)는 결합법칙과 교환법칙에 의해 A⊕B이기 때문이다.
풀이 과정
결국 문제가 모든 ai를 같게 만들어야 하므로, 우리는 정점 간에 다음 값을 구해야만 한다.
루트 노드의 번호를 r라고 하고, i번째 정점의 부모를 p(i)라고 할 때 다음과 같다.
mr=i=r∑si⋅(ai⊕ap(i))
어차피 본인보다 상위 정점에서 연산을 해봤자 (ai⊕ap(i)) 값 자체는 변하지 않기 때문이다.
그럼 이 문제는 결국 si를 잘 구하면 되는 문제로 변형된다.
일단 루트 노드 vr에서 mr을 구했다고 가정하자.
이때, vr의 자식 중 하나를 vs라고 하면, ms를 구할 때 변하는 건 트리의 크기뿐이다.
vs를 루트노드라고 하면, 원래 vs를 루트로 하는 서브트리의 크기(ss)를 변경된 트리에서 vr을 루트로 하는 서브트리의 크기(sr)로 바꿔주기만 하면 된다.
그럼 다음 식으로 ms를 구할 수 있다.
ms=mr+(as⊕ar)⋅(sr−ss)
sr과 ss는 한 개의 간선으로 나뉘어지는 노드의 개수이다. 따라서, 이는 각 간선마다 미리 구해둘 수 있다. (O(N))