题意:输入一颗二叉树的中序,先序,q个询问,每次询问两个节点的lca。
思路:求dfs序,st表维护dfs序中的高度,map映射一下每个值对应的节点序号,rmq求lca。预处理查询
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
const int MAX_N = 10010;
int n, m, r, x, y;
int lc[MAX_N], rc[MAX_N], pre[MAX_N], in[MAX_N], fs[MAX_N];
int dfsorder[MAX_N<<2], height[MAX_N<<2], len = 0;
map<int, int > mp;
int build(int il, int ir, int pl, int pr) {
if (il >= ir) return -1;
if (ir - il == 1) return pl;
int rt = pl, p = -1;
for (int i = il; i < ir; i++) {
if (in[i] == pre[rt]) {
p = i; break;
}
}
lc[rt] = build(il, p, pl+1, pl+1+p-il);
rc[rt] = build(p+1, ir, pl+1+p-il, pr);
return rt;
}
void dfs(int rt, int h) {
if (rt == -1) return ;
fs[rt] = len; dfsorder[len] = rt; height[len] = h; len++;
if (lc[rt] != -1) {dfs(lc[rt], h+1); dfsorder[len] = rt; height[len] = h; len++;}
if (rc[rt] != -1) {dfs(rc[rt], h+1); dfsorder[len] = rt; height[len] = h; len++;}
}
int st[MAX_N<<1][30];
void init(int size) {
for (int i = 0; i < size; i++) st[i][0] = i;
for (int j = 1; 1<<j <= size; j++) {
for (int i = 0; i + (1 << j) -1 < size; i++) {
int a = st[i][j-1];
int b = st[i+(1<<(j-1))][j-1];
if (height[a] < height[b]) st[i][j] = a;
else st[i][j] = b;
}
}
}
int rmq(int L, int R) {
int k = (int)log2(1.0*(R-L+1));
int a = st[L][k];
int b = st[R-(1<<k)+1][k];
if (height[b] > height[a]) return a;
else return b;
}
int lca(int x, int y) {
int l = fs[x];
int r = fs[y];
if (l > r) swap(l, r);
return pre[dfsorder[rmq(l, r)]];
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
memset(lc, -1, sizeof(lc)); memset(rc, -1, sizeof(rc));
memset(fs, -1, sizeof(fs));
scanf("%d %d", &m, &n);
for (int i = 0; i < n; i++) scanf("%d", &in[i]);
for (int i = 0; i < n; i++) {scanf("%d", &pre[i]); mp[pre[i]] = i;}
r = build(0, n, 0, n);
dfs(r, 0);
init(len);
for (int i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
if (mp.count(x) && mp.count(y)) {
int id1 = mp[x], id2 = mp[y];
int res = lca(id1, id2);
if (res == x) printf("%d is an ancestor of %d.\n", x, y);
else if (res == y) printf("%d is an ancestor of %d.\n", y, x);
else printf("LCA of %d and %d is %d.\n", x, y, res);
} else {
if (mp.count(x)) printf("ERROR: %d is not found.\n", y);
else if (mp.count(y)) printf("ERROR: %d is not found.\n", x);
else {
printf("ERROR: %d and %d are not found.\n", x, y);
}
}
}
return 0;
}
代码(暴力也能过)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
const int MAX_N = 10010;
int n, m, x, y, r;
int in[MAX_N], pre[MAX_N], lc[MAX_N], rc[MAX_N];
map<int, int> mp;
int build(int il, int ir, int pl, int pr) {
if (il >= ir) return -1;
if (ir - il == 1) return pl;
int rt = pl, p = -1;
for (int i = il; i < ir; i++) {
if (in[i] == pre[rt]) {
p = i; break;
}
}
lc[rt] = build(il, p, pl+1, pl+1+p-il);
rc[rt] = build(p+1, ir, pl+1+p-il, pr);
return rt;
}
void lca(int x, int y) {
int p = r, v = pre[r];
int tx = mp[x], ty = mp[y];
for(;;) {
int tp = mp[v];
if ((tx < tp && tp < ty) || (ty < tp && tp < tx)) {
printf("LCA of %d and %d is %d.\n", x, y, v); return ;
} else if (tx < tp && ty < tp) {
p = lc[p]; v = pre[p];
} else if (tx > tp && ty > tp) {
p = rc[p]; v = pre[p];
} else if (tx == tp) {
printf("%d is an ancestor of %d.\n", x, y); return ;
} else if (ty == tp) {
printf("%d is an ancestor of %d.\n", y, x); return ;
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%d %d", &m, &n);
memset(lc, -1, sizeof(lc)); memset(rc, -1, sizeof(rc));
for (int i = 0; i < n; i++) {
scanf("%d", &in[i]);
mp[in[i]] = i;
}
for (int i = 0; i < n; i++) scanf("%d", &pre[i]);
r = build(0, n, 0, n);
for (int i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
if (!mp.count(x) && !mp.count(y)) {
printf("ERROR: %d and %d are not found.\n", x, y);
} else if (!mp.count(x)) {
printf("ERROR: %d is not found.\n", x);
} else if (!mp.count(y)) {
printf("ERROR: %d is not found.\n", y);
} else {
lca(x, y);
}
}
return 0;
}