题目(不是板子!)-最近公共祖先(LCA)
第4题 最近公共祖先 查看测评数据信息
小 Soup 正在翻看他们家的族谱,他们家的族谱构成了一棵树。小 Soup 发现,由于年代久远,他们家族中的一些分支已经绝迹,他对此十分好奇。
小 Soup 给你他们家的族谱树,想要问你在这棵树中所有第 k 层的孩子(树中深度为 k 的点,根节点的深度为 1 ,根节点编号为 1 )的最近公共祖先是谁。
输入格式
第一行两个整数 n,m。
第二行 n 个整数,其中第 i 个整数为 f[i],表示 i 的父亲为 f[i],请注意,1 的 f[i] 固定为 0。
接下来 m 行,每行一个整数 k,代表小 Soup 的询问。
%20 n[1,10],m[1,10]
%20 n[1,100],m[1,100]
%20 n[1,1000],m[1,1000]
%20 n[1,100000],m[1,100000]
%20 n[1,5000000],m[1,5000000]
输出格式
对于每个小 Soup 的询问,输出一个整数,即所有深度为 k 的点的最近公共祖先。
输入/输出例子1
输入:
8 3
0 1 1 2 2 3 4 5
2
1
4
输出:
1
1
2
样例解释
无
两个思路
1.记录每层中最左,最右的节点,找最左最右最近公共祖先 ( 缺证)
2.自底向上bfs,记录所有答案
这里只讨论第一种。
关于最左最右很好整,最左是dfs中最先到的那个点,最右是dfs中最后到的那个点,分别记录即可。
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int n, m, x, k, vis[N], dep[N], first[N], last[N];
int f[N][25];
vector<int> a[N];
void dfs(int u, int fa)
{
if (vis[u]) return ;
vis[u]=1;
dep[u]=dep[fa]+1;
f[u][0]=fa;
for (int i=1; (1<<i)<=dep[u]; i++)
f[u][i]=f[f[u][i-1]][i-1];
if (!first[dep[u]]) first[dep[u]]=u;
last[dep[u]]=u;
for (int i=0; i<a[u].size(); i++)
{
int v=a[u][i];
if (v!=fa) dfs(v, u);
}
}
int lca(int x, int y)
{
if (dep[x]<dep[y]) swap(x, y);
for (int i=24; i>=0; i--)
if (dep[f[x][i]]>=dep[y]) x=f[x][i];
if (x==y) return x;
for (int i=24; i>=0; i--)
if (f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
return f[x][0];
}
int main()
{
scanf("%d%d", &n, &m);
for (int i=1; i<=n; i++)
{
scanf("%d", &x);
a[x].push_back(i);
a[i].push_back(x);
}
dep[1]=1;
dfs(1, 0);
while (m--)
{
scanf("%d", &k);
printf("%d\n", lca(first[k], last[k]));
}
return 0;
}

浙公网安备 33010602011771号