#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
int num=0;
int head[1000005]={0},nxt[1000005]={0},to[1000005]={0};
int f[500005][23]={0},deep[500005]={0}; //f[x][i] x向上走2的i次方步
int n,m,r;
void add(int x,int y)
{
nxt[++num]=head[x];
head[x]=num;
to[num]=y;
}
void dfs(int x,int fa)
{
f[x][0]=fa; deep[x]=deep[fa]+1;
for(int i=head[x];i;i=nxt[i])
if(deep[to[i]]==0) dfs(to[i],x);
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y); //x更深
for(int i=22;i>=0;i--)
if(deep[f[x][i]]>=deep[y]) x=f[x][i]; //x倍增爬到与y同层
if(x==y) return x; //y是x祖先
for(int i=22;i>=0;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; //一起爬呀
return f[x][0]; //找爸爸
}
int main()
{
scanf("%d%d%d",&n,&m,&r);
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
} //存图
deep[0]=0; dfs(r,0); //简直重要的不要不要的啦
for(int i=1;i<=22;i++)
for(int j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];//O(nlogn)的初始化
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));//在线的询问
}
return 0;
}
在线的lca O((m+n)log n)
离线的等我学会再说啊,呵呵
1.定义 F[点数][log 点数] deep[点数] (核心数组)
邻接表存图
2.无根树转有根树(有父亲 儿子关系)————dfs (伴随着求出deep,deep同时充当b数组) F[root][0]=0; deep[0]=0;
3.灰常重要的初始化 ————F[root][0]=0; deep[0]=0;
O(nlogn) 的dp F的二维是状态啊啊
4. LCA ———— 看标程注释 22不用改 数组开够就行