//LCA
//ST表 在线
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define maxn 500001
using namespace std;
int n,m,cnt,root,head[maxn],depth[maxn];
int order[2*maxn],first[maxn];//order[x]dfs中第x次遍历的点(重复) first[x]记录点x在dfs中首次遍历顺序(不重复)
int lg[2*maxn],f[2*maxn][21];//lg[x]记录log2x的向下取整值 f[x][k]表示包含x点共2^k个点中最小值
struct uio{
int next,to;
}edge[2*maxn];
void add(int x,int y)
{
edge[++cnt].next=head[x];
edge[cnt].to=y;
head[x]=cnt;
}
void dfs(int x,int pre)//pre为上次遍历过节点 防止走重
{
order[++cnt]=x;
first[x]=cnt;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int u=edge[i].to;
if(u!=pre)
{
depth[u]=depth[x]+1;
dfs(u,x);
order[++cnt]=x;
}
}
}
void ST()
{
for(int i=1;i<=cnt;i++)
f[i][0]=order[i];
lg[1]=0,lg[2]=1;
for(int i=3;i<=cnt;i++)
{
lg[i]=lg[i-1];
if(1<<lg[i-1]+1==i)
lg[i]++;
}
int num=lg[cnt];
for(int j=1;j<=num;j++)
for(int i=1;i+(1<<j)-1<=cnt;i++)// i+(1<<j)-1 -1原因:区间包括自身
{
if(depth[f[i][j-1]]<depth[f[i+(1<<j-1)][j-1]])
f[i][j]=f[i][j-1];
else
f[i][j]=f[i+(1<<j-1)][j-1];
}
}
int RMQ(int l,int r)
{
int k=lg[r-l+1];
if(depth[f[l][k]]<depth[f[r-(1<<k)+1][k]])//r-(1<<k)+1 +1原因:区间包括自身
return f[l][k];
else return f[r-(1<<k)+1][k];//此处+1原因同上
}
int ask(int x,int y)
{
x=first[x];
y=first[y];
if(x>y)
swap(x,y);
return RMQ(x,y);
}
int main()
{
scanf("%d%d%d",&n,&m,&root);
memset(head,-1,sizeof(head));
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
cnt=0;
dfs(root,-1);
ST();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d %d",&u,&v);
printf("%d\n",ask(u,v));
}
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4361557/blog/3912488