倍增法求LCA模板 / p3379


前言

倍增法主要分为三个步骤:

  1. 读入图后,进行遍历,获得deep[]深度数组和fa[i][0]父节点数组
  2. 进行dp/状态转移获得 f a [ i ] [ 2 j ] fa[i][2^j] fa[i][2j],即第 2 j 2^j 2j个祖先
  3. 对于待查询点u, v,先让它们到达统一深度,再去循环访问它们的第 2 j 2^j 2j个祖先

至此,便完成了整个查询过程,时间复杂度是 O ( n log ⁡ n ) + q O ( log ⁡ n ) O(n \log n)+qO(\log n) O(nlogn)+qO(logn),q是查询次数

一、例题 p3379

二、思路及代码

1.思路

纯模板题,直接套板子

2.代码

代码如下:

#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 500005;
struct e {
  int to, next;
} edge[maxn << 1];
int head[maxn], cnt;
int n, m, root;
int deep[maxn], f[maxn][21];  // f[i][j]: i的第2^j层的祖先
void init() {
  cnt = 0;
  memset(head, -1, sizeof(head));
  for (int i = 0; i < maxn; i++) edge[i].next = -1;
}
void addedge(int u, int v) {
  edge[cnt] = e{v, head[u]};
  head[u] = cnt++;
}
void dfs(int u, int fa) {
  deep[u] = deep[fa] + 1;
  f[u][0] = fa;
  for (int i = head[u]; i != -1; i = edge[i].next) {
    if (edge[i].to == fa) continue;
    dfs(edge[i].to, u);
  }
}
void LCApre() {
  deep[0] = 0;
  dfs(root, 0);
  for (int i = 1; i <= 20; i++)  // f[][0]为递归基
    for (int u = 1; u <= n; u++) f[u][i] = f[f[u][i - 1]][i - 1];
}
int LCA(int u, int v) {
  if (deep[u] < deep[v]) swap(u, v);  //保证deep[u] > deep[v]
  for (int i = 20; i >= 0; i--) {
    if (deep[f[u][i]] >= deep[v]) u = f[u][i];
  }  // 此时 deep[u] = deep[v]
  if (u == v) return u;
  for (int i = 20; i >= 0; i--) {
    if (f[u][i] != f[v][i]) {
      u = f[u][i];
      v = f[v][i];
    }
  }  // 此时 f[u][i] = f[v][i]
  return f[u][0];
}
int main() {
  //   freopen("in.txt", "r", stdin);
  //   freopen("out.txt", "w", stdout);
  init();
  int u, v;
  scanf("%d%d%d", &n, &m, &root);
  for (int i = 0; i < n - 1; ++i) {
    scanf("%d%d", &u, &v);
    addedge(u, v);
    addedge(v, u);
  }
  LCApre();
  for (int i = 0; i < m; ++i) {
    scanf("%d%d", &u, &v);
    printf("%d\n", LCA(u, v));
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值