题目链接
思路
板子题,LCA有据我所知有暴力求法(过于暴力),树上倍增求法,tarjan(只能离线O(1)查询,不会)
vector 存图,需要氧气优化才能过,可能我写丑了。
链式前向星存图,开氧气优化效果倒不是很明显。
代码
#include <bits/stdc++.h>
using namespace std;
vector<int> e[500005];
//int tot = 0, first[500005];
//struct Node
//{
// int v, next;
//}e[1000005];
//void add(int u, int v)
//{
// e[tot].v = v;
// e[tot].next = first[u];
// first[u] = tot++;
//}
int deep[500005], f[500005][20], lg2[500005];
void dfs(int u, int fa)
{
deep[u] = deep[fa]+1;
f[u][0] = fa;
for(int i = 1; (1<<i) < deep[u]; ++i) f[u][i] = f[f[u][i-1]][i-1];
for(auto v : e[u]) if(v != fa) dfs(v,u);
// for(int i = first[u]; ~i; i = e[i].next)
// {
// int v = e[i].v;
// if(v != fa) dfs(v,u);
// }
}
int lca(int x, int y)
{
if(deep[x] > deep[y]) swap(x,y);
while(deep[y] > deep[x]) y = f[y][lg2[deep[y]-deep[x]]];
if(x == y) return x;
for(int i = lg2[deep[x]]; ~i; --i) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int main()
{
int n, m, root;
// tot = 0;
// memset(first,-1,sizeof(first));
scanf("%d%d%d",&n,&m,&root);
for(int i = 2; i <= n; ++i)
{
int u, v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
// add(u,v);
// add(v,u);
}
dfs(root,0);
for(int i = 1; i <= n; ++i) lg2[i] = lg2[i-1]+(1<<lg2[i-1] == i); // 求 [log2(i)+1]
for(int i = 1; i <= n; ++i) --lg2[i];
while(m--)
{
int a, b;
scanf("%d%d",&a,&b);
printf("%d\n",lca(a,b));
}
return 0;
}