반응형

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

 

3176번: 도로 네트워크

첫째 줄에 N이 주어진다. (2 ≤ N ≤ 100,000) 다음 N-1개 줄에는 도로를 나타내는 세 정수 A, B, C가 주어진다. A와 B사이에 길이가 C인 도로가 있다는 뜻이다. 도로의 길이는 1,000,000보다 작거나 같은 양

www.acmicpc.net

 

N개의 도시는 N-1개의 도로로 연결되어있습니다.

즉, 사이클이 없는 그래프 형태이므로 트리 구조의 일종이라고 볼 수 있습니다.

두 도시를 연결하는 경로에서 가장 짧은 도로의 길이와 가장 긴 도로의 길이를 빠르기 구하기 위해서 LCA를 이용하였습니다.

minDist[i][j] = i번 노드의 2^j번 조상 노드까지 가장 짧은 도로 길이

maxDist[i][j] = i번 노드의 2^j번 조상 노드까지 가장 긴 도로 길이를 전처리해줍니다.

두 도시를 d, e라고 할 때,

d에서 lca(d, e)까지의 가장 짧거나 긴 도로 길이,

e에서 lca(d, e)까지의 가장 짧거나 긴 도로 길이를 구해줄 것입니다.

d와 e 중에서 더 깊은 노드를 같은 높이를 맞추는 과정, lca(d, e)까지 상위 노드로 올라오는 과정 속에서,

가장 짧거나 긴 도로의 길이를 계속해서 업데이트해줍니다.

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

int n, m;
vector<pair<int, int>> graph[100001];
int p[100001][17]; // p[i][j] = i번 노드의 2^j번 조상 노드
int minDist[100001][17]; // xxxDist[i][j] = i번 노드의 2 ^ j번 
int maxDist[100001][17]; // 조상 노드까지 가장 (짧은, 긴) 도로 길이
int d[100001]; // d[i] = i번 노드의 깊이

void init(int node, int depth, int val) {
	d[node] = depth;
	minDist[node][0] = val;
	maxDist[node][0] = val;
	for (pair<int,int>& edge : graph[node]) {
		int next = edge.first;
		int cost = edge.second;
		if (d[next] != -1) continue;
		p[next][0] = node;
		init(next, depth + 1, cost);
	}
}

pair<int, int> lca(int u, int v) {
	int minRes = 1e6, maxRes = 0;
	if (d[u] > d[v]) swap(u, v); // v가 더 깊도록 스왑
	int diff = d[v] - d[u]; // v의 깊이를 u의 깊이까지 올려줌
	for (int i = 0; diff != 0; i++) {
		if (diff & 1) {
			minRes = min(minRes, minDist[v][i]);
			maxRes = max(maxRes, maxDist[v][i]);
			v = p[v][i];
		}
		diff >>= 1;
	}

	if (u == v) return {minRes, maxRes};

	for (int i = 16; i >= 0; i--) {
		if (p[u][i] != p[v][i]) {
			minRes = min({ minRes, minDist[u][i], minDist[v][i] });
			maxRes = max({ maxRes, maxDist[u][i], maxDist[v][i] });
			u = p[u][i];
			v = p[v][i];
		}
	}
	return {
		min({minRes, minDist[u][0], minDist[v][0]}),
		max({maxRes, maxDist[u][0], maxDist[v][0]})
	};
}

int main() {
	int a, b, c;
	memset(d, -1, sizeof(d));

	scanf("%d", &n);
	for (int i = 1; i < n; i++) {
		scanf("%d %d %d", &a, &b, &c);
		graph[a].push_back({b, c});
		graph[b].push_back({a, c});
	}

	init(1, 0, 0);

	for (int i = 1; i < 17; i++) {
		for (int j = 1; j <= n; j++) {
			p[j][i] = p[p[j][i - 1]][i - 1];
			minDist[j][i] = min(minDist[j][i - 1], minDist[p[j][i - 1]][i - 1]);
			maxDist[j][i] = max(maxDist[j][i - 1], maxDist[p[j][i - 1]][i - 1]);
		}
	}
	scanf("%d", &m);
	for (int i = 0; i < m; i++) {
		scanf("%d %d", &a, &b);
		pair<int, int> ans = lca(a, b);
		printf("%d %d\n", ans.first, ans.second);
	}
}
반응형

'Algorithm' 카테고리의 다른 글

백준 1929 : 소수 구하기  (0) 2021.11.18
백준 1978 : 소수 찾기  (0) 2021.11.18
백준 15480 : LCA와 쿼리  (0) 2021.11.18
백준 11438 : LCA 2  (0) 2021.11.18
백준 17435 : 합성함수와 쿼리  (0) 2021.11.18

+ Recent posts