L
C
A
模
板
—
—
洛
谷
P
3379
LCA 模板——洛谷P3379
LCA模板——洛谷P3379
原题:P3379 【模板】最近公共祖先(LCA)
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const int V=5*1e5+100;
ll n,m,s,top,x,y;
ll k,d[V],head[V],f[V][25];
ll len,t;
struct node
{
ll next,to;
}e[V<<1];
void add(ll x,ll y)
{
e[++top]=node{head[x],y};
head[x]=top;
}
void dfs(ll x,ll y)
{
d[x]=d[y]+1;
f[x][0]=y;
for(r ll i=head[x];i;i=e[i].next)
{
ll v=e[i].to;
if(v!=y) dfs(v,x);//深搜
}
}
ll LCA(ll x,ll y)
{
if(d[x]>d[y]) swap(x,y);//保证大小
len=d[y]-d[x];
k=20,t=1<<k;
while(len)
{
if(len>=t)
y=f[y][k],len-=t;//y先跳到与x同层(倍增)
t>>=1,--k;
}
if(x==y) return x; //特判:一个点是另一个店的祖先
k=20;
while(k>=0)
{
if(f[x][k]!=f[y][k]) //一起跳
{
x=f[x][k];
y=f[y][k];
}
--k;
}
return f[x][0];
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&s);
rep(i,1,n-1)
{
scanf("%lld%lld",&x,&y);
add(x,y);
add(y,x);
}
dfs(s,0);
for(r ll j=1;(1<<j)<=V;++j)
rep(i,1,n)
f[i][j]=f[f[i][j-1]][j-1]; //预处理,f[i][j]表示从i向根走2^j步点的编号
rep(i,1,m)
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",LCA(x,y));
}
return 0;
}