//方法一
vector<int>G[MAX_N];//输入 图的邻接表
int root;//根节点
int parent[MAX_N];//父亲节点
int depth[MAX_N];//节点深度
void dfs(int v,int p,int d)
{
parent[v]=p;
depth[v]=d;
for(int i=0;i<G[v].size();i++)
if(G[v][i]!=p)
dfs(G[v][i],v,d+1);
}
void init()
{
dfs(root,-1,0);
}
int LCA(int u,int v)
{
while(depth[u]>depth[v])
u=parent[u];
while(depth[v]>depth[u])
v=parent[v];
while(u!=v)
{
u=parent[u];
v=parent[v];
}
}
//方法二
vector<int>G[MAX_N];
int root;
int parent[MAX_LOG_N][MAX_N];
int depth[MAX_N];
void dfs(int v,int p,int d)
{
parent[0][v]=p;
depth[v]=d;
for(int i=0;i<G[v].size();i++)
if(G[v][i]!=p)
dfs(G[v][i],v,d+1);
}
void init(int V)
{
dfs(root,-1,0);
for(int k=0;k+1<MAX_LOG_N;k++)
{
for(int v=0;v<V;v++)
{
if(parent[k][v]<0)
parent[k+1][v]=-1;
else
parent[k+1][v]=parent[k][parent[k][v]];
}
}
}
int LCA(int u,int v)
{
if(depth[u]>depth[v])
swap(u,v);
for(int k=0;k<MAX_LOG_N;k++)
{
if(depth[v]-depth[u]>>k&1)
v=parent[k][v];
}
if(u==v)
return u;
for(int k=MAX_LOG_N;k>=0;k--)
{
if(parent[k][u]!=parent[k][v])
{
u=parent[k][u];
v=parent[k][v];
}
}
return parent[0][u];
}
//方法三
vector<int>G[MAX_N];
int root;
int vs[MAX_N*2-1]; //dfs访问的顺序
int depth[MAX_N*2-1];
int id[MAX_N]; // 各个顶点在vs中首次出现的下标
void dfs(int v,int p,int d,int &k)
{
id[v]=k;
vs[k]=v;
depth[k++]=d;
for(int i=0;i<G[v].size();i++)
{
if(G[v][i]!=p)
{
dfs(G[v][i],v,d+1,k);
vs[k]=v;
depth[k++]=d;
}
}
}
void init(int V)
{
int k=0;
dfs(root,-1,0,k);
rmq_init(depth,V*2-1);
}
int LCA(int u,int v)
{
return vs[query(min(id[u],id[v]),max(id[u],id[v])+1);
}