[백준] 3176 - 도로 네트워크 (Python)

sudog·2023년 8월 27일
0

백준

목록 보기
13/15

도시가 NN개 존재하고 도로가 N1N-1개 존재하므로 트리 형태인 것을 알 수 있다. 따라서 경로를 찾기 위해서는 최소 공통 조상 알고리즘을 사용하고, 빠르게 찾기 위해 희소 배열을 사용한다.

이 문제에서는 경로 상에서 가장 짧은 도로와 가장 긴 도로를 찾아내야 하므로 각각 배열로 만들어 갱신해야 한다.

import sys
input = sys.stdin.readline


def make_tree():
    que = [1]
    # bfs로 순회하면서 희소 배열을 생성한다.
    for node in que:
        visit[node] = 1
        for i in range(1, 17):
            if not parent[i-1][node]:
                break
            parent[i][node] = parent[i-1][parent[i-1][node]]
            # 2^i 번째 조상까지 연결된 도로의 최소, 최대
            min_edge[i][node] = min(min_edge[i-1][node], min_edge[i-1][parent[i-1][node]])
            max_edge[i][node] = max(max_edge[i-1][node], max_edge[i-1][parent[i-1][node]])
        for b, c in graph[node]:
            if visit[b]:
                continue
            # 자식 노드의 1번째 조상은 node임
            parent[0][b] = node
            min_edge[0][b] = c
            max_edge[0][b] = c
            depth[b] = depth[node]+1
            que.append(b)
        
def find_lca(a, b):
    min_res = 1_000_001
    max_res = 0
    # depth[a] > depth[b]를 항상 유지한다.
    a, b = (a, b) if depth[a] >= depth[b] else (b, a)
    # 두 노드의 깊이를 일치시킨다.
    while depth[a] != depth[b]:
        for i in range(1, 18):
        	# 조상이 없거나 깊이가 얕아지는 경우 그 이전 조상으로 이동한다.
            if not parent[i][a] or depth[parent[i][a]] < depth[b]:
                min_res = min(min_res, min_edge[i-1][a])
                max_res = max(max_res, max_edge[i-1][a])
                a = parent[i-1][a]
                break
    if a == b:
        return (min_res, max_res)
    # 공통 조상을 찾을 때 최소한으로 올라가야 하므로 부모가 같으면 바로 종료한다.
    while parent[0][a] != parent[0][b]:
        for i in range(1, 18):
        	# 조상이 같은 경우에는 최소한으로 올라왔는지 알 수 없다.
            if not parent[i][a] or parent[i][a] == parent[i][b]:
                min_res = min(min_res, min_edge[i-1][a], min_edge[i-1][b])
                max_res = max(max_res, max_edge[i-1][a], max_edge[i-1][b])
                a = parent[i-1][a]
                b = parent[i-1][b]
                break
    min_res = min(min_res, min_edge[0][a], min_edge[0][b])
    max_res = max(max_res, max_edge[0][a], max_edge[0][b])
    return (min_res, max_res)

n = int(input())
graph = [[] for _ in range(n+1)]
visit = [0]*(n+1)
min_edge = [[1_000_001]*(n+1) for _ in range(18)]
max_edge = [[0]*(n+1) for _ in range(18)]
parent = [[0]*(n+1) for _ in range(18)]
depth = [0]*(n+1)
depth[1] = 1
for _ in range(n-1):
    a, b, c = map(int, input().rstrip().split())
    graph[a].append((b, c))
    graph[b].append((a, c))

make_tree()
k = int(input())
for _ in range(k):
    a, b = map(int, input().rstrip().split())
    print(*find_lca(a, b))
profile
안녕하세요

0개의 댓글