본문 바로가기

PS - 알고리즘

24520 - Meet In The Middle

step 1

더보기

신촌 왕국은 트리 구조로 되어 있습니다. 두 사람의 위치가 s, e라고 하겠습니다.

 

1번 영역은 항상 s가 더 가깝습니다.

2번 영역은 항상 e가 더 가깝습니다.

만약 초록색 점이 답이라고 가정하면 빨간 점이 각 마을까지 거리의 합이 더 짧으므로 모순이 생깁니다.

즉, s와 e 사이의 경로에 답이 있습니다.

step 2

더보기

LCA를 이용해서 두 점 사이의 거리를 구할 수 있습니다. 

그리고 LCA를 이용해서 s나 e에서 특정 거리만큼 떨어진 경로 위의 점을 구할 수 있습니다.

LCA를 구할 때 dfs로 하면 메모리가 터질 수 있습니다.

코드

더보기
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
vector<pair<long long int, long long int>> v[200000];
queue<pair<long long int, long long int>> qq;
long long int mapp[200000][30],lv[200000], mapg[200000][30];
long long int gx, gy;
long long int lca(long long int x, long long int y) {
	long long int p = lv[y] - lv[x], i;
	for (i = 20;i >= 0;i--) {
		if (p >= (1 << i)) {
			gy += mapg[y][i];
			y = mapp[y][i];
			p -= (1 << i);
		}
	}
	if (x == y) return x;
	for (i = 20;i >= 0;i--) {
		if (mapp[x][i] != mapp[y][i]) {
			gx += mapg[x][i];
			gy += mapg[y][i];
			x = mapp[x][i];
			y = mapp[y][i];
		}
	}
	gx += mapg[x][0];
	gy += mapg[y][0];
	x = mapp[x][0];
	y = mapp[y][0];
	return x;
}
long long int up(long long int i, long long int g) {
	long long int j;
	for (j = 20;j >= 0;j--) {
		if (mapp[i][j] == 0) continue;
		if (g >= mapg[i][j]) {
			g -= mapg[i][j];
			i = mapp[i][j];
		}
	}
	if (g == 0) return i;
	else return -1;
}
int main() {
	long long int n, q, i, j;
	scanf("%lld%lld", &n, &q);
	for (i = 1;i < n;i++) {
		long long int x, y, z;
		scanf("%lld%lld%lld", &x, &y, &z);
		//x = i; y = i + 1; z = 1000000000;
		v[x].push_back({ y,z });
		v[y].push_back({ x,z });
	}
	qq.push({ 1,0 });
	while (qq.size()) {
		int i = qq.front().first, p = qq.front().second;
		qq.pop();
		mapp[i][0] = p;
		lv[i] = lv[p] + 1;
		for (j = 1;j < 20;j++) {
			mapp[i][j] = mapp[mapp[i][j - 1]][j - 1];
			mapg[i][j] = mapg[i][j - 1] + mapg[mapp[i][j - 1]][j - 1];
		}
		for (j = 0;j < v[i].size();j++) {
			if (v[i][j].first == p) continue;
			mapg[v[i][j].first][0] = v[i][j].second;
			qq.push({ v[i][j].first, i });
		}
	}
 	while (q--) {
		long long int x, y,p;
		scanf("%lld%lld", &x, &y);
		gx = 0; gy = 0;
		if (lv[x] > lv[y]) swap(x, y);
		p = lca(x, y);
		if ((gx + gy) % 2 != 0) { printf("-1\n"); continue; }
		if (gx == gy) { printf("%lld\n", p); continue; }
		else if (gx > gy) printf("%lld\n", up(x, (gx + gy) / 2));
		else if (gx < gy) printf("%lld\n", up(y, (gx + gy) / 2));
	}
	return 0;
}

'PS - 알고리즘' 카테고리의 다른 글

11025 - 요세푸스 문제 3  (0) 2024.10.14
23755 - 카드컨트롤 (Hard)  (0) 2024.10.07
10479 - 따르릉 따르릉  (0) 2024.09.23
1314 - 동굴 탐험  (0) 2024.09.16
31725 - 포닉스와 달구  (0) 2024.09.09