1. 根据前序和中序序列建二叉树,同时记录每个结点的父结点
2. 从查询结点x开始向上走,经过的结点标记1,直到根结点;y向上走,遇到第一个标记为1的结点即为x、y的最近公共祖先
3. map会超时,unordered_map不超时
#include <iostream>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <set>
#include <cmath>
#include <queue>
#include <deque>
#include <ctime>
#include <unordered_map>
#include <algorithm>
#include <cstdlib>
#define ll long long
using namespace std;
int m, n, preOrder[10010], inOrder[10010];
unordered_map<int, int> posIn, v, parent;
struct node {
int lc, rc;
};
unordered_map<int, struct node> t;
int build(int inL, int inR, int preL, int preR) {
int root = preOrder[preL]; // 根结点为前序序列的第一个结点
int k = posIn[root]; // k记录该结点在中序序列中的位置
// 若还有左子树,则递归找到root的左孩子
if(k > inL) {
t[root].lc = build(inL, k - 1, preL + 1, preL - inL + k);
parent[t[root].lc] = root;
}
// 若还有右子树,则递归找到root的右孩子
if(k < inR) {
t[root].rc = build(k + 1, inR, preR - inR + k + 1, preR);
parent[t[root].rc] = root;
}
return root; // 返回根结点
}
int main() {
cin >> m >> n;
for(int i = 1; i <= n; i++) {
cin >> inOrder[i];
posIn.insert(make_pair(inOrder[i], i)); // 记录结点在中序序列中的位置
}
for(int i = 1; i <= n; i++) cin >> preOrder[i];
int root = build(1, n, 1, n);
// dfs(root); // 找父结点
while(m--) {
int x, y;
cin >> x >> y;
if(!posIn[x] && !posIn[y]) {
printf("ERROR: %d and %d are not found.\n", x ,y);
continue;
}
if(!posIn[x]) {
printf("ERROR: %d is not found.\n", x);
continue;
}
if(!posIn[y]) {
printf("ERROR: %d is not found.\n", y);
continue;
}
v.clear();
int p = x, ans = 0;
while (1) {
v[p] = 1;
if(p == root) break;
p = parent[p];
}
p = y;
while(1) {
if(v[p]) {
ans = p;
break;
}
v[p] = 1;
if(p == root) break;
p = parent[p];
}
if(ans == x)
printf("%d is an ancestor of %d.\n", x, y);
else if(ans == y)
printf("%d is an ancestor of %d.\n", y, x);
else printf("LCA of %d and %d is %d.\n", x, y, ans);
}
}