문제 풀이

[BOJ] 3176 | 도로 네트워크

문제

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

풀이

sparse table을 이용한 LCA 문제.

LCA를 구현하고, 다음과 같은 DP 테이블을 만든다.

maxi[i][j] = i의 j번째 조상까지의 도로중 가장 긴 도로의 길이.

maxi[i][j] = max(maxi[parent[i][j - 1]][j - 1], maxi[i][j-1]);

maxi[i][j] = i의 j번째 조상까지의 도로중 가장 짧은 도로의 길이.

mini[i][j] = min(mini[parent[i][j - 1]][j - 1], mini[i][j - 1]);

이를 잘 이용하여 풀면 된다.

sparse-table 초기화에 O(NlogN)

쿼리 실행 중, 두 노드의 높이를 맞추는데 O(logN), 가장 긴/짧은 도로를 찾는데 O(logN)이므로,

쿼리 실행의 시간복잡도는 O(QlogN).

전체 시간복잡도는 O((Q+N)logN)

소스

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#define P pair<int,int>
using namespace std;

int n, q, depth[110000], mini[110000][20], maxi[110000][20], parent[110000][20];

vector<P> G[110000];
queue<int> Q;

int main() {
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n;
	for (int i = 1; i < n; i++) {
		int a, b, c;
		cin >> a >> b >> c;
		G[a].push_back({ b,c });
		G[b].push_back({ a,c });
	}
	depth[1] = 1;
	parent[1][0] = 1;
	Q.push(1);
	while (!Q.empty()) {
		int now = Q.front();
		Q.pop();
		for (P nxt : G[now]) {
			if (!depth[nxt.first]) {
				depth[nxt.first] = depth[now] + 1;
				mini[nxt.first][0] = nxt.second;
				maxi[nxt.first][0] = nxt.second;
				parent[nxt.first][0] = now;
				Q.push(nxt.first);
			}
		}
	}
	for (int i = 1; i < 20; i++)
		for (int j = 1; j <= n; j++) {
			parent[j][i] = parent[parent[j][i - 1]][i - 1];
			maxi[j][i] = max(maxi[parent[j][i - 1]][i - 1], maxi[j][i-1]);
			mini[j][i] = min(mini[parent[j][i - 1]][i - 1], mini[j][i - 1]);
		}
	cin >> q;
	while (q--) {
		int a, b, dismax=0, dismin=1000000;
		cin >> a >> b;
		if (depth[a] < depth[b])
			swap(a, b);
		int diff = depth[a] - depth[b];
		for(int i=0; diff; i++) {
			if (diff & 1) {
				dismax = max(dismax, maxi[a][i]);
				dismin = min(dismin, mini[a][i]);
				a = parent[a][i];
			}
			diff /= 2;
		}
		if (a != b) {
			for (int i = 19; i >= 0; i--) {
				if (parent[a][i] != parent[b][i]) {
					dismax = max({ dismax, maxi[a][i], maxi[b][i] });
					dismin = min({ dismin, mini[a][i], mini[b][i] });
					a = parent[a][i], b = parent[b][i];
				}
			}
			dismax = max({ dismax, maxi[a][0], maxi[b][0] });
			dismin = min({ dismin, mini[a][0], mini[b][0] });
		}
		cout << dismin << " " << dismax << "\n";
	}
}
← 문제 풀이 글 더 보기