LCA是什么?
最近公共祖先,就是树上的两个点它们深度最大(离根节点最远)的公共祖先。

算法
1. 朴素算法。时间复杂度O(n×q)。并没有实际意义。
2. 倍增算法。时间复杂度O((n+q)logn)

倍增算法
它的特点是:每次向祖先跳的距离,不是1,而是2k,这样可以省很多时间。
记录每个点的fai,j,表示i号节点向根跳2j步的点,如果跳过了根记为0。那么显然,第一步是要把要询问的两个节点都跳到同一深度,第二步同时往根跳。这样就找到了这两个点的LCA。

代码

#include <cstdio>
#include <algorithm>

const int maxn=500000;

inline int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
    {
      f=-f;
    }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

inline int print(int x,int mode=0)
{
  if(!mode)
    {
      if(!x)
    {
      putchar('0');
      return 0;
    }
      if(x<0)
    {
      putchar('-');
      x=-x;
    }
    }
  if(x)
    {
      print(x/10,1);
      putchar(x%10+'0');
    }
  return 0;
}

struct tree
{
  int pre[maxn*2+10],now[maxn+10],son[maxn*2+10],tot;
  int deep[maxn+10],fa[maxn+10][20];

  int ins(int a,int b)//建图
  {
    tot++;
    pre[tot]=now[a];
    now[a]=tot;
    son[tot]=b;
    return 0;
  }

  int dfs(int u,int father)//预处理,把每个点的fa都处理出来
  {
    deep[u]=deep[father]+1;
    fa[u][0]=father;
    for(int i=1; i<=19; i++)
      {
    fa[u][i]=fa[fa[u][i-1]][i-1];
      }
    int j=now[u];
    while(j)
      {
    int v=son[j];
    if(v!=father)
      {
        dfs(v,u);
      }
    j=pre[j];
      }
    return 0;
  }

  int lca(int x,int y)//求LCA
  {
    if(deep[x]<deep[y])
      {
    std::swap(x,y);
      }
    for(int i=19; i>=0; i--)
      {
    if(deep[fa[x][i]]>=deep[y])
      {
        x=fa[x][i];//将深度大点的往上跳,当然不能跳过另一个点
      }
      }
    if(x==y)
      {
    return x;//如果找到答案了退出
      }
    for(int i=19; i>=0; i--)
      {
    if(fa[x][i]!=fa[y][i])//同时向上跳,当然不能跳到一起去
      {
        x=fa[x][i];
        y=fa[y][i];
      }
      }
    return fa[x][0];//最后再跳到一起,那么这个点一定是LCA
  }
};

tree t;
int n,m,root;

int main()
{
  n=read();
  m=read();
  root=read();
  for(int i=1; i<n; i++)
    {
      int a=read(),b=read();
      t.ins(a,b);
      t.ins(b,a);
    }
  t.dfs(root,0);
  while(m--)
    {
      print(t.lca(read(),read()));
      putchar('\n');
    }
  return 0;
}