반응형

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

 

15480번: LCA와 쿼리

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N-1개의 줄에는 트리 T의 간선 정보 u와 v가 주어지다. u와 v는 트리의 간선을 나타내는 두 정점이다. 다음 줄에는 쿼리의 개수 M(

www.acmicpc.net

 

만약 각 루트마다 sparse table을 새로 만들어준다면, 시간 안에 모든 쿼리 결과를 구할 수 없게 됩니다.

1번 노드를 루트로 sparse table을 한 번만 만들어두면, 이를 통해 각 쿼리 결과를 구할 수 있습니다.

입력 값 r, u, v에 대하여 1번 노드가 루트인 트리와 비교했을 때, 다음과 같은 상황이 있을 수 있습니다.

1) u와 v가 루트 r의 자손 노드인 경우

* 쿼리 결과는 lca(u, v)

2) u 또는 v 중 하나만 루트 r의 자손 노드인 경우

* 루트의 자손인 노드를 x라고 할 때, lca(r, x)는 루트 r이 됩니다.

* 루트의 자손이 아닌 노드를 y라고 할 때, lca(r, y)는 루트 r의 조상 노드 중 하나입니다.

* lca(u, v)는 루트 r의 조상 노드 중 하나입니다.

* 따라서, 쿼리 결과는 가장 깊은 곳에 있는 루트 r입니다.

3) u와 v가 루트 r의 자손 노드가 아닌 경우

* 쿼리 결과는 lca(r, u)와 lca(r, v) 중에서 더 깊은 곳에 있는 노드

* 위에서 구한 두 개의 노드는 lca(u, v)보다는 더 큰 깊이를 가집니다.

따라서, lca(u, v), lca(r, u), lca(r, v) 중에서 가장 깊은 곳에 있는 노드를 구하면 됩니다.

 

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

int n, m;
vector<int> graph[100001];
int p[100001][17]; // p[i][j] = i번 노드의 2^j번 조상 노드
int d[100001]; // d[i] = i번 노드의 깊이

void init(int node, int depth) {
	d[node] = depth;
	for (int i = 0; i < graph[node].size(); i++) {
		if (d[graph[node][i]] != -1) continue;
		p[graph[node][i]][0] = node;
		init(graph[node][i], depth + 1);
	}
}

int lca(int a, int b) {
	if (d[a] > d[b]) swap(a, b); // b가 더 깊도록 스왑
	int diff = d[b] - d[a]; // b의 깊이를 a의 깊이까지 올려줌
	for (int i = 0; diff != 0; i++) {
		if (diff & 1) {
			b = p[b][i];
		}
		diff >>= 1;
	}
	if (a == b) return a;
	for (int i = 16; i >= 0; i--) {
		if (p[a][i] != p[b][i]) {
			a = p[a][i];
			b = p[b][i];
		}
	}
	return p[a][0];
}

int main() {
	int r, a, b, ans, res;
	memset(d, -1, sizeof(d));
	scanf("%d", &n);
	for (int i = 1; i < n; i++) {
		scanf("%d %d", &a, &b);
		graph[a].push_back(b);
		graph[b].push_back(a);
	}

	init(1, 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];
		}
	}

	scanf("%d", &m);
	for (int i = 0; i < m; i++) {
		scanf("%d %d %d", &r, &a, &b);
		ans = res = lca(a, b);
		if (d[(res = lca(a, r))] > d[ans]) ans = res;
		if (d[(res = lca(b, r))] > d[ans]) ans = res;
		printf("%d\n", ans);
	}
}
반응형

'Algorithm' 카테고리의 다른 글

백준 1978 : 소수 찾기  (0) 2021.11.18
백준 3176 : 도로 네트워크  (0) 2021.11.18
백준 11438 : LCA 2  (0) 2021.11.18
백준 17435 : 합성함수와 쿼리  (0) 2021.11.18
백준 3584 : 가장 가까운 공통 조상  (0) 2021.11.18

+ Recent posts