1. 程式人生 > >CS20 D LCA

CS20 D LCA

mes its brush 題解 http com nbsp namespace amp

給出一棵樹,許多詢問,每次詢問A,B,C三點,求一點使到三點距離最小,輸出該點和最小值。

很明顯就是求LCA,三種組合都求一次LCA,然後在裏面選個距離和最小的就行了。

官方題解裏面的代碼求LCA是在線DFS RMQ的方法..先記錄歐拉序,且記錄某個點在序列裏的第一個位置,每次詢問a,b的LCA就是詢問兩者在歐拉序列裏第一個位置之差中的那些點裏面深度最小的

LCA(a,b)=RMQ(dep, pos[a], pos[b])

/** @Date    : 2017-09-27 20:41:28
  * @FileName: CS20 C LCA RMQ.cpp
  * @Platform: Windows
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int dep[N];
int pos[N];
int rmq[19][2*N];
int eul[2*N], c, l[2*N];

vector<int> edg[N];


void dfs(int x, int pre)
{
	eul[++c] = x;
	pos[x] = c;
	if(pre) dep[x] = dep[pre] + 1;
	for(auto i: edg[x])
	{
		if(i == pre)
			continue;
		dfs(i, x);
		eul[++c] = x;
	}
}

void init()
{
	dfs(1, 0);
	for(int i = 2; i <= c; i++)//預處理 2^k=x對應的k 
		l[i] = l[i / 2] + 1;
	for(int i = 1; i <= c; i++)
		rmq[0][i] = eul[i];
	for(int j = 1; (1 << j) <= c; j++)
		for(int i = 1; i <= c; i++)
		{
			rmq[j][i] = rmq[j - 1][i];
			if(i + (1 << (j - 1)) > c)
				continue;
			if(dep[rmq[j - 1][i + (1 << (j - 1))]] < dep[rmq[j][i]])
				rmq[j][i] = rmq[j - 1][i + (1 << (j - 1))];
		}
}

int lca(int x, int y)
{
	if(pos[x] > pos[y])
		swap(x, y);
	int dis = pos[y] - pos[x] + 1;
	int k = l[dis];
	if(dep[rmq[k][pos[x] + dis - (1 << k)]] 
		< dep[rmq[k][pos[x]]])
		return rmq[k][pos[x] + dis - (1 << k)];
	else return rmq[k][pos[x]];
}

int distance(int a, int b)
{
	int ac = lca(a, b);
	return dep[a] + dep[b] - 2 * dep[ac];
}
int main()
{
	int n, q;
	cin >> n >> q;
	for(int i = 0; i < n - 1; i++)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		edg[x].PB(y);
		edg[y].PB(x);
	}
	init();
	while(q--)
	{
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		int ac1 = lca(a, b);
		int ac2 = lca(a, c);
		int ac3 = lca(b, c);
		int ans1 = distance(ac1, a) + distance(ac1, b) + distance(ac1, c);
		int ans2 = distance(ac2, a) + distance(ac2, b) + distance(ac2, c);
		int ans3 = distance(ac3, a) + distance(ac3, b) + distance(ac3, c);
		if(ans1 > ans2)
			swap(ans1, ans2), swap(ac1, ac2);
		if(ans1 > ans3)
			swap(ans1, ans3), swap(ac1, ac3);
		printf("%d %d\n", ac1, ans1);
	}
    return 0;
}

CS20 D LCA