倍增

#define forGraph(g,u,v,i) for(int i=g.fst[u],v=g.to[i];i;i=g.nxt[i],v=g.to[i])
int n,k;
struct Graph {
    int fst[MAXN], nxt[MAXN<<1], to[MAXN<<1], tot;
    void add(int u,int v) {
        to[++tot]=v;
        nxt[tot]=fst[u];
        fst[u]=tot;
    }
}g;
int f[MAXN][20], Log[MAXN], depth[MAXN];
void dfs(int i,int pre) {
    if(i!=1) f[i][0]=pre;
    depth[i]=depth[pre]+1;
    forGraph(g,i,j,edge) if(j!=pre) dfs(j,i,edge);
}
void init() {
    Log[1]=0; for(int i=2;i<=n;i++) Log[i]=Log[i/2]+1;
    for(int j=1;j<=Log[n];j++) 
        for(int i=1;i<=n;i++) 
            f[i][j]=f[f[i][j-1]][j-1];
}
int lca(int x,int y) {
    if (depth[x]<depth[y]) swap(x,y);
    int d=depth[x]-depth[y];
    for(int i=0;i<=Log[d];i++) if(d&(1<<i)) x=f[x][i];
    if (x==y) return x;
    for(int j=Log[depth[y]];j>=0;j--) 
        if (f[x][j] && f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
    return f[x][0];
}
int main() {
    scanf("%d", &n);
    for(int i=1;i<n;i++) {
        int u,v;
        scanf("%d%d", &u, &v);
        g.add(u,v);
        g.add(v,u);
    }
    dfs(1,1);
    init();
    scanf("%d", &k);
    for(int i=1;i<=k;i++) {
        int x,y;
        scanf("%d%d", &x, &y);
        printf("%d\n", lca(x,y)));
    }
    return 0;
}

在线($\mathrm{DFS}$序+$\mathrm{RMQ}$)

#define forGraph(g,u,v,i) for(int i=g.fst[u],v=g.to[i];i;i=g.nxt[i],v=g.to[i])
int n,k;
struct Graph {
    int fst[MAXN], nxt[MAXN<<1], to[MAXN<<1], tot;
    void add(int u,int v) {
        to[++tot]=v;
        nxt[tot]=fst[u];
        fst[u]=tot;
    }
}g;
int first[MAXN],dNum;
int lis[MAXN<<1], Log[MAXN], depth[MAXN], st[MAXN<<1][20];
void dfs(int i,int pre) {
    depth[i]=depth[pre]+1;
    first[i]=++dNum;
    lis[dNum]=i;
    forGraph(g,i,j,edge) if(j!=pre) {
        dfs(j,i,edge);
        lis[++dNum]=i;
    }
}
void init() {
    Log[1]=0; for(int i=2;i<=dNum;i++) Log[i]=Log[i/2]+1;
    for(int i=1;i<=dNum;i++) st[i][0]=i;
    for(int j=1;j<=Log[dNum];j++) 
        for(int i=1;i+(1<<j)-1<=dNum;i++) {
            int a=st[i][j-1],b=st[i+(1<<(j-1))][j-1];
            st[i][j]=depth[lis[a]]<depth[lis[b]]?a:b;
        }
}
int lca(int x,int y) {
    x=first[x],y=first[y];
    if (x>y) swap(x,y);
    int len=Log[y-x+1];
    int a = st[x][len], b=st[y-(1<<len)+1][len];
    return lis[depth[lis[a]]<depth[lis[b]]?a:b];
}
int main() {
    scanf("%d", &n);
    for(int i=1;i<n;i++) {
        int u,v;
        scanf("%d%d", &u, &v);
        g.add(u,v);
        g.add(v,u);
    }
    dfs(1,1);
    init();
    scanf("%d", &k);
    for(int i=1;i<=k;i++) {
        int x,y;
        scanf("%d%d", &x, &y);
        printf("%d\n", lca(x,y)));
    }
    return 0;
}

离线($\mathrm{Tarjan}$算法)

#define forGraph(g,u,v,i) for(int i=g.fst[u],v=g.to[i];i;i=g.nxt[i],v=g.to[i])
int n,k;
struct Graph {
    int fst[MAXN], nxt[MAXN<<1], to[MAXN<<1], w[MAXN<<1], tot;
    void add(int u,int v,int ww) {
        to[++tot]=v;
        nxt[tot]=fst[u];
        fst[u]=tot;
        w[tot]=ww;
    }
}g,ask;
int fa[MAXN],asks[MAXN][2],ans[MAXN];
bitset<MAXN> vis;
int find(int x) {
    if (fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
void unite(int x,int y) {
    x=find(x),y=find(y);
    if (x!=y) fa[x]=y;
}
void lca(int i) {
    fa[i]=i;
    vis[i]=1;
    forGraph(g,i,j,edge) {
        if (!vis[j]) {
            lca(j);
            unite(j,i);
        }
    }
    forGraph(ask,i,j,edge) {
        if (vis[j]) ans[ask.w[edge]]=find(j);
    }
}
int main() {
    scanf("%d", &n);
    for(int i=1;i<n;i++) {
        int u,v;
        scanf("%d%d", &u, &v);
        g.add(u,v,0);
        g.add(v,u,0);
    }
    scanf("%d", &k);
    for(int i=1;i<=k;i++) {
        scanf("%d%d", &asks[i][0], &asks[i][1]);
        ask.add(asks[i][0],asks[i][1],i);
        ask.add(asks[i][1],asks[i][0],i);
    }
    lca(1);
    for(int i=1;i<=k;i++) printf("%d\n", ans[i]);
    return 0;
}