pat1151 LCA in a Binary Tree

题意:输入一颗二叉树的中序,先序,q个询问,每次询问两个节点的lca。

思路:求dfs序,st表维护dfs序中的高度,map映射一下每个值对应的节点序号,rmq求lca。预处理O(nlogn)查询O(1)

代码

#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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值