본문 바로가기
문제 해결/BOJ

[백준] LCA

by 자잘 2023. 2. 21.

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

 

11437번: LCA

첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정

www.acmicpc.net

문제 제목 그대로 LCA 문제입니다. 일반적인 DFS로는 시간초과가 발생할 것 같아서 DP와 결합된 LCA알고리즘을 활용하여 풀이하였습니다. 

 

import sys
from collections import defaultdict
from math import log, ceil

sys.setrecursionlimit(10 ** 6)

# sys.stdin = open("input.txt", "r")


input = sys.stdin.readline


graph = defaultdict(list)

n = int(input())

h = ceil(log(n) / log(2)) + 1

# 각 정점의 깊이
depth = [0] * (n + 1)

# parent[i][j]: i번 노드의 2 ^ j승번째 부모 노드
parent = [
    [0] * (h)
    for _ in range(n + 1)
]

for _ in range(n - 1):
    n1, n2 = tuple(map(int, input().split()))
    graph[n1].append(n2)
    graph[n2].append(n1)


def dfs(cur, d, pa):
    depth[cur] = d
    parent[cur][0] = pa

    for next_node in graph[cur]:
        if next_node != pa and depth[next_node] == 0:
            dfs(next_node, d + 1, cur)


def lca(a, b):
    # 항상 b가 더 깊게
    if depth[a] > depth[b]:
        a, b = b, a

    # 높이 맞추기
    for i in range(h - 1, -1, -1):
        if (1 << i) <= depth[b] - depth[a]:
            b = parent[b][i]

    if a == b:
        return a

    # 최소 공통 부모를 찾는 과정
    for i in range(h - 1, -1, -1):
        if parent[a][i] != parent[b][i]:
            a = parent[a][i]
            b = parent[b][i]

    return parent[a][0]


# 깊이와 부모노드 기록
dfs(1, 1, 0)

# 부모 노드들을 기록한다.
for i in range(1, h):
    for j in range(1, n + 1):
        parent[j][i] = parent[parent[j][i - 1]][i - 1]

m = int(input())

for _ in range(m):
    a, b = tuple(map(int, input().split()))
    print(lca(a, b))

'문제 해결 > BOJ' 카테고리의 다른 글

[백준] 벽 부수고 이동하기 2  (0) 2023.02.22
[백준] 감시  (0) 2023.02.21
[백준] 당근 훔쳐 먹기  (0) 2023.02.20
[백준] 정복자  (0) 2023.02.19
[백준] 같이 눈사람 만들래?  (0) 2023.02.18