对于每一个节点,记录其深度
求LCA时,试图用较深的点交汇较浅的点
最后两点同时上跳,直到交汇
优化细节处理,例如lg的边界问题
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define ri register int
using namespace std;
int qread() {
int x = 0 ;
char ch = getchar ( ) ;
while (ch > '9' || ch < '0') ch = getchar ( ) ;
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0' ;
ch = getchar ( ) ;
}
return x ;
}
const int maxn = 500001,maxm = 500001,maxlg=19;
int n,m,s,x,y,en=0;
struct edge {
int fr,gt,nxt;
};
edge e [maxm*2];
int head[maxn],lg[maxn],f[maxn][23],dpt[maxn];
void adg(int x,int y) {
++en;
e[en].fr=x;
e[en].gt=y;
e[en].nxt=head[x];
head[x]=en;
}
void dfs(int x,int fa) {
dpt[x]=dpt[fa]+1;
f[x][0]=fa;
for (int i=1;i<=23;i++){
f[x][i]=f[f[x][i-1]][i-1];
if(f[x][i]==0)break;
//cout<<f[x][i]<<endl;
}
for (ri i=head[x]; i; i=e[i].nxt) {
if(e[i].gt==fa)continue;
dfs (e[i].gt,x);
}
}
int LCA (int x,int y) {
if(dpt[x]<dpt[y]) {
int t=x;
x=y;
y=t;
}
while (dpt[x]>dpt[y]){
x=f[x][lg[dpt[x]-dpt[y]]-1];
}
// cout<<x<<' '<<y<<endl;
if(x==y)return x;
for (int i=lg[dpt[x]];i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i];y=f[y][i];
}
}
return f[x][0];
}
int main() {
// freopen("3379.in","r",stdin);
memset(head,0,sizeof(head));
n=qread();
m=qread();
s=qread();
for (ri i=1; i<n; ++i) {
x=qread();
y=qread();
adg(x,y);
adg(y,x);
}
for (ri i=1; i<=n; ++i)lg[i]=lg[i-1]+(1<<lg[i-1]==i);
dpt[0]=0;
dfs(s,0);
// for (ri i=1; i<=n; ++i)cout<<i<<' '<<0<<' '<<f[i][0]<<endl;
for (ri i=1; i<=m; ++i) {
x=qread();
y=qread();
cout<<LCA(x,y)<<endl;
}
// for (int i=1;i<=n;i++){
// for (int j=1;j<=26;j++){
// cout<<f[i][j]<<' ';
// }
// cout<<endl;
// }
fclose (stdin);
fclose (stdout);
return 0;
}