【ACWing】1644. 二叉树中的最低公共祖先

【ACWing】1644. 二叉树中的最低公共祖先,第1张

题目地址:

https://www.acwing.com/problem/content/description/1646/

树中两个结点 U U U V V V的最低公共祖先(LCA)是指同时具有 U U U V V V作为后代的最深结点。给定二叉树中的任何两个结点,请你找到它们的LCA。

输入格式:
第一行包含两个整数 M M M N N N,分别表示询问结点对数以及二叉树中的结点数量。接下来两行,每行包含 N N N个不同的整数,分别表示二叉树的中序和前序遍历。保证二叉树可由给定遍历序列唯一确定。接下来 M M M行,每行包含两个整数 U U U V V V,表示一组询问。所有结点权值均在int范围内。

输出格式:
对于每对给定的UV,输出一行结果。
如果UV的LCA是A,且A不是UV,则输出LCA of U and V is A.
如果UV的LCA是A,且AUV中的一个,则输出X is an ancestor of Y.,其中X表示AY表示另一个结点。
如果UV没有在二叉树中找到,则输出ERROR: U is not found.ERROR: V is not found.ERROR: U and V are not found.

数据范围:
1 ≤ M ≤ 1000 1≤M≤1000 1M1000
1 ≤ N ≤ 10000 1≤N≤10000 1N10000

先根据中序遍历和先序遍历把树递归构造出来,接着用倍增法做预处理来求最近公共祖先即可,参考https://blog.csdn.net/qq_46105170/article/details/116217633。节点值有负数,需要做离散化。代码如下:

#include 
#include 
#include 
#include 
using namespace std;

const int N = 1e4 + 10;
int n, m;
int root, chd[N][2];
int pre[N], in[N], map[N];
int c[N];
int dep[N], f[N][15];
int q[N];

// 求x离散化之后的编号
int get(int x) {
  int l = 1, r = n;
  while (l < r) {
    int mid = l + (r - l + 1 >> 1);
    if (x >= c[mid]) l = mid;
    else r = mid - 1;
  }

  if (c[l] != x) return -1;
  return l;
}

// 递归建树
int dfs(int pl, int pr, int il, int ir) {
  if (pl > pr) return 0;
  int u = pre[pl], lc = map[u] - il, rc = ir - map[u];
  chd[u][0] = dfs(pl + 1, pl + lc, il, map[u] - 1);
  chd[u][1] = dfs(pl + lc + 1, pr, map[u] + 1, ir);
  return u;
}

void bfs() {
  memset(dep, -1, sizeof dep);
  dep[root] = 0;
  int hh = 0, tt = 0;
  q[tt++] = root;
  while (hh < tt) {
    int t = q[hh++];
    for (int i = 0; i <= 1; i++) {
      int v = chd[t][i];
      if (v && dep[v] == -1) {
        dep[v] = dep[t] + 1;
        f[v][0] = t;
        for (int k = 1; 1 << k <= dep[v]; k++)
          f[v][k] = f[f[v][k - 1]][k - 1];
        
        q[tt++] = v;
      }
    }
  }
}

int lca(int a, int b) {
  if (dep[a] < dep[b]) swap(a, b);
  for (int k = 0, diff = dep[a] - dep[b]; 1 << k <= diff; k++)
    if (diff >> k & 1) a = f[a][k];
  
  if (a == b) return a;

  for (int k = log2(dep[a]); k >= 0; k--)
    if (f[a][k] != f[b][k])
      a = f[a][k], b = f[b][k];
  
  return f[a][0];
}

int main() {
  scanf("%d%d", &m, &n);
  for (int i = 1; i <= n; i++) {
    scanf("%d", &in[i]);
    c[i] = in[i];
  }
  for (int i = 1; i <= n; i++) scanf("%d", &pre[i]);
  sort(c + 1, c + n + 1);
  for (int i = 1; i <= n; i++) {
    pre[i] = get(pre[i]), in[i] = get(in[i]);
    map[in[i]] = i;
  }

  root = dfs(1, n, 1, n);
  bfs();

  while (m--) {
    int a, b;
    scanf("%d%d", &a, &b);
    int x = a, y = b;
    a = get(a), b = get(b);
    if (a == -1 && b == -1)
      printf("ERROR: %d and %d are not found.\n", x, y);
    else if (a == -1)
      printf("ERROR: %d is not found.\n", x);
    else if (b == -1)
      printf("ERROR: %d is not found.\n", y);
    else {
      int p = lca(a, b);
      if (p == a) printf("%d is an ancestor of %d.\n", x, y);
      else if (p == b) printf("%d is an ancestor of %d.\n", y, x);
      else printf("LCA of %d and %d is %d.\n", x, y, c[p]);
    }
  }
}

预处理时间复杂度 O ( N log ⁡ N ) O(N\log N) O(NlogN),每次询问时间复杂度 O ( log ⁡ N ) O(\log N) O(logN),空间 O ( N log ⁡ N ) O(N\log N) O(NlogN)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/921553.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存