LCA是什么?
最近公共祖先,就是树上的两个点它们深度最大(离根节点最远)的公共祖先。
算法
1. 朴素算法。时间复杂度
2. 倍增算法。时间复杂度
倍增算法
它的特点是:每次向祖先跳的距离,不是
记录每个点的
代码
#include <cstdio>
#include <algorithm>
const int maxn=500000;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline int print(int x,int mode=0)
{
if(!mode)
{
if(!x)
{
putchar('0');
return 0;
}
if(x<0)
{
putchar('-');
x=-x;
}
}
if(x)
{
print(x/10,1);
putchar(x%10+'0');
}
return 0;
}
struct tree
{
int pre[maxn*2+10],now[maxn+10],son[maxn*2+10],tot;
int deep[maxn+10],fa[maxn+10][20];
int ins(int a,int b)//建图
{
tot++;
pre[tot]=now[a];
now[a]=tot;
son[tot]=b;
return 0;
}
int dfs(int u,int father)//预处理,把每个点的fa都处理出来
{
deep[u]=deep[father]+1;
fa[u][0]=father;
for(int i=1; i<=19; i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
int j=now[u];
while(j)
{
int v=son[j];
if(v!=father)
{
dfs(v,u);
}
j=pre[j];
}
return 0;
}
int lca(int x,int y)//求LCA
{
if(deep[x]<deep[y])
{
std::swap(x,y);
}
for(int i=19; i>=0; i--)
{
if(deep[fa[x][i]]>=deep[y])
{
x=fa[x][i];//将深度大点的往上跳,当然不能跳过另一个点
}
}
if(x==y)
{
return x;//如果找到答案了退出
}
for(int i=19; i>=0; i--)
{
if(fa[x][i]!=fa[y][i])//同时向上跳,当然不能跳到一起去
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];//最后再跳到一起,那么这个点一定是LCA
}
};
tree t;
int n,m,root;
int main()
{
n=read();
m=read();
root=read();
for(int i=1; i<n; i++)
{
int a=read(),b=read();
t.ins(a,b);
t.ins(b,a);
}
t.dfs(root,0);
while(m--)
{
print(t.lca(read(),read()));
putchar('\n');
}
return 0;
}