lca转RMQ

时间:2021-11-02 20:25:45

这个博客写得好

 #include <stdio.h>
#include <vector>
#include <string.h>
using namespace std;
const int N = ; /*
lca 转RMQ 询问u和v的lca
我们保存树的遍历序列,那么只要在序列中找到第一次出现u和第一次出现v的位置
然后RMQ该区间深度最小的那个点就是u和v的lca了 那么要保存每个点首次出现的位置
还要保存遍历序列的dep序列,然后RMQ dep序列得到哪一位置的dep最小
然后映射为结点
*/ vector<int> g[N];
int total;
int id[N];
int dep[N];
int ref[N];
int dp[N][];
int pos[N][];
void dfs(int u, int fa, int d)
{
id[u] = ++total;
dep[total] = d;//去
ref[total] = u;
for(int i=;i<g[u].size(); ++i)
{
int v = g[u][i];
if(v==fa)continue;
dfs(v,u,d+);
dep[++total] = d;//回来
ref[total] = u;
} } void init()
{
int n = total;
for(int i=;i<=n;++i)
dp[i][] = i; for(int j=;(<<j)<=n;++j)
{
for(int i=;i+(<<j)-<=n;++i)
{
int a = dp[i][j-];
int b = dp[i+(<<(j-))][j-];
if(dep[a] < dep[b])
dp[i][j] = a;
else
dp[i][j] = b;
}
}
}
int query(int u, int v)
{
if(id[u] > id[v])
swap(u,v);
int L = id[u];
int R = id[v];
int k = ;
while(<<(k+)<=R-L+)k++;
int a = dp[L][k];
int b = dp[R-(<<k)+][k];
if(R[a]<R[b])
{
return ref[a];
}
else
return ref[b];
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=;i<=n;++i)
g[i].clear();
int u,v;
for(int i=;i<n;++i)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
total = ;
dep[] = ;
dfs(,-,);
init();
int m;
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&u,&v);
printf("%d\n",query(u,v));
}
}
return ;
}