其实这个LCA没啥优化(主要是因为博主太弱了QwQ)
首先,什么是LCA? :
指在有根树中,找出某两个结点u和v最近的公共祖先。
那什么是倍增呢? :
是指将在树上的u点与v点同时向上传递时,每次不是指移一位,而是移位从而大大提高时间效率。(预处理为O(nlogn),之后的挨次询问为O(logn) )。
(为了时间,我二话不说地使用了链式向前星与快读QwQ)
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=500005;
int head[2*maxn],d[maxn],f[maxn][25];
int cnt,n,m,s;
struct node{
int next,to;
}a[2*maxn];
void add(int x,int y){//向前星
++cnt;
a[cnt].to=y;
a[cnt].next=head[x];
head[x]=cnt;
}
void dfs(int x,int fa){//搜索的预处理
d[x]=d[fa]+1;
f[x][0]=fa;
for(int i=1;(1<<i)<=d[x];i++){
f[x][i]=f[f[x][i-1]][i-1];//动规处理
}
for(int i=head[x];i;i=a[i].next){
int y=a[i].to;
if(y!=fa){
dfs(y,x);
}
}
}
int lca(int x,int y){
if(d[x]<d[y]){
swap(x,y);
}
int i=-1;
while((1<<(i+1))<=d[x]){
i++;
}
for(int j=i;j>=0;j--){//下移
if(d[x]-(1<<j)>=d[y]){
x=f[x][j];
}
}
if(x==y)
return x;
for(int j=i;j>=0;j--){//同时向上跳
if(f[x][j]!=f[y][j]){
x=f[x][j];
y=f[y][j];
}
}
return f[x][0];//由于判断式为f[x][j]==f[y][j],返回的应该为两个点共同的父亲。
}
int read(){
int re=0;
char ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9'){
re=re*10+ch-'0';
ch=getchar();
}
return re;
}
int main(){
n=read();m=read();s=read();
FOR(i,1,n-1){
int x,y;
x=read();y=read();
add(x,y);
add(y,x);
}
dfs(s,0);
FOR(i,1,m){
int x,y;
x=read();y=read();
printf("%d\n",lca(x,y));
}
return 0;
}