倍增LCA模板

注意!本篇题解不适合初学LCA的同学学习,因为我讲的很烂很不清楚。

倍增,顾名思义,就是成倍增加的意思。

我们知道,任何一个数字都可以表示成二进制。那么对于一条长度为n的链,我们总是可以跳大概logn次到达最后。

对于链上任意一点,我们都可以在大概logn的复杂度下询问到,其实倍增的思路就是二分,和快速幂一模一样。

那么怎么用倍增求LCA呢?

首先在树上求每个节点的深度,并且更新每个节点的祖先节点。假如有A和B两个结点,我们就假设深度大的为A,我们可以在logn的复杂度下跳到B的深度,然后A和B同时在logn的复杂度下跳到LCA。

所以倍增求LCA的复杂度是logn的啦。

下面上代码吧:(这是一份常数极大的模板,慎用。)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+7;
const int maxl = 21;
int fa[maxn][maxl];
int depth[maxn];
int lg[maxn];
vector<int> G[maxn];
void dfs(int now,int last)
{
	depth[now] = depth[last]+1;
	fa[now][0] = last;
	for(int i=1;(1<<i)<=depth[now];i++)
	{
		fa[now][i] = fa[fa[now][i-1]][i-1];
	}
	for(int i=0;i<G[now].size();i++)
	{
		if(G[now][i]!=last) dfs(G[now][i],now);
	}
}
int lca(int x,int y)
{
	if(depth[x]>depth[y]) swap(x,y);
	while(depth[x]!=depth[y]) y = fa[y][lg[depth[y]-depth[x]]-1];
	if(x==y) return x;
	for(int k=lg[depth[y]];k>=0;k--)
	{
		if(fa[x][k]!=fa[y][k])
		{
			x = fa[x][k];
			y = fa[y][k];
		}
	}
	return fa[x][0];
}
int main()
{
	int n,m,s;
	scanf("%d%d%d",&n,&m,&s);
	int x,y;
	for(int i=0;i<n-1;i++)
	{
		scanf("%d%d",&x,&y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	for(int i=1;i<=n;i++)
	{
		lg[i] = lg[i-1]+(1<<lg[i-1]==i);
	}
	dfs(s,0);
	for(int i=0;i<m;i++)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",lca(x,y));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/84193351