题目(不是板子!)-最近公共祖先(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; }