写在前面
- 思路分析
- 无须构建树,递归每1层得到树的根结点,通过lca算法确定两个结点公共祖先
-
lca
自定义函数 - 已知某树根结点
- a和b在根结点左边,则a和b最近公共祖先在当前子树根结点的左子树寻找
- a和b在当前子树根结点两边,当前子树根结点就是a和b的最近公共祖先
- a和b在当前子树根结点右边,则a和b的最近公共祖先在当前子树右子树寻找
- 新知识盲点,学习ing
- 第1遍略懂
测试用例
input:
6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99
output:
LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.
ac代码
- 参考链接
#include <iostream>
#include <vector>
#include <map>
using namespace std;
map<int, int> pos;
vector<int> in, pre;
void lca(int inl, int inr, int preRoot, int a, int b)
{
if(inl > inr) return;
int inRoot = pos[pre[preRoot]], aIn = pos[a], bIn=pos[b];
if(aIn < inRoot && bIn < inRoot)
lca(inl, inRoot-1, preRoot+1, a, b);
else if((aIn < inRoot && bIn>inRoot) || (aIn>inRoot && bIn<inRoot))
printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);
else if(aIn > inRoot && bIn > inRoot)
lca(inRoot+1, inr, preRoot+1+(inRoot-inl), a, b);
else if(aIn == inRoot)
printf("%d is an ancestor of %d.\n", a, b);
else if(bIn == inRoot)
printf("%d is an ancestor of %d.\n", b, a);
}
int main()
{
int m, n, a, b;
scanf("%d %d", &m,&n);
in.resize(n+1), pre.resize(n+1);
for(int i=1; i<=n; i++)
{
scanf("%d", &in[i]);
pos[in[i]] = i;
}
for(int i=1; i<=n; i++) scanf("%d", &pre[i]);
for(int i=0; i<m; i++)
{
scanf("%d %d", &a, &b);
if(pos[a] == 0 && pos[b]==0)
printf("ERROR: %d and %d are not found.\n", a, b);
else if(pos[a]==0 || pos[b]==0)
printf("ERROR: %d is not found.\n", pos[a] == 0 ? a : b);
else
lca(1, n, 1, a, b);
}
return 0;
}
知识点小结
-
LCA(Least Common Ancestors)
- 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。
- 主要用途
- 用来处理当两个点仅有唯1条确定的最短路径时的路径。