题解:
1.用bfs建立层级数组、倍增数组
2.倍增法求LCA 传送门
3.线段树的ST表实现,求一段区间的LCA
AC code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+1000;
const int DEG = 20;
int n;
int head[maxn];
int f[maxn][20];
int st[maxn][20];
int dep[maxn];
int tot;
struct edge
{
int to,next;
}es[maxn<<1];
void add_edge(int u, int v)
{
es[tot].to = v;
es[tot].next = head[u];
head[u] = tot++;
}
void bfs(int root)
{
f[root][0] = root;
dep[root] = 0;
queue<int> q;
q.push(root);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = 1; i < DEG; i++)
f[u][i] = f[f[u][i-1]][i-1];
for(int i = head[u]; i != -1; i = es[i].next)
{
int v = es[i].to;
if(f[u][0] == v) continue;
f[v][0] = u;
dep[v] = dep[u]+1;
q.push(v);
}
}
}
int LCA(int u,int v)
{
if(dep[u] < dep[v]) swap(u,v);
for(int det = dep[u]-dep[v], i = 0; det ; det >>= 1, i++)
if(det & 1) u = f[u][i];
if(u == v) return u;
for(int i = DEG-1; i >= 0; i--)
if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i];
return f[u][0];
}
int main()
{
while(scanf("%d",&n) != EOF)
{
tot = 0;
memset(head,-1,sizeof(head));
memset(f,-1,sizeof(f));
int u,v;
for(int i = 0; i < n-1; i++)
{
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
bfs(1);
for(int i = 1; i <= n; i++) st[i][0] = i;
for(int j = 1; j < 20; j++)
for(int i = 1; i+ (1<<(j-1)) <= n; i++)
st[i][j] = LCA(st[i][j-1],st[i+(1<<(j-1))][j-1]);
int q;
scanf("%d",&q);
int l,r;
while(q--)
{
scanf("%d%d",&l,&r);
int k = log2(r-l+1);
int ans = LCA(st[l][k],st[r-(1<<k)+1][k]);
printf("%d\n",ans);
}
}
return 0;
}