倍增法求LCA——在线
Posted E-Valley
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了倍增法求LCA——在线相关的知识,希望对你有一定的参考价值。
推荐 B站视频讲解
首先我们考虑暴力做法:
分别从两个点开始一层一层地向上跳,直到跳到一样的点,这个点就是他俩的LCA了。
这个做法实在太暴力了,不可取,不可取. . .
于是我们找到了一个不那么暴力的做法——倍增法。
我们可以用倍增来在线求LCA(其(da)实(gai)就是一跳跳好几层)。
设 fa[i][j] 记录从 i 点向上跳 2j 层所到达的点,fa数组是预处理得出的(还有每个点的深度deep也是),后面会说。
_____________先看LCA的求法____________________________________________
我们知道对于两个点的位置有两种情况:
① 位于同一层:
这时只要两个点一起跳,直到跳到相同的点即可。
for (int i = 20; i >= 0; i--) { if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } }
② 不同层:
将深度更深的点向上跳到与另一个点同一层,即转化为①。
if (node[x].deep < node[y].deep) { int t = x; // 保证 x 是更深的那个点 x = y; y = t; } for (int i = 0; i <= 20; i++) { if ((node[x].deep - node[y].deep)>> i & 1) x = fa[x][i]; } if (x == y) return x; // 特判:两个点在同一条链上的情况(即:它们其中一个点就是它俩的LCA)
______________预处理__________________________________________________
一个 dfs 搞定(从根结点开始DFS)。
void dfs(int s) { for (int k = 1; k <= 20; k++) fa[s][k] = fa[fa[s][k - 1]][k - 1]; for (Edge *e = node[s].last; e; e = e->next) { if (!e->to->deep) { e->to->deep = node[s].deep + 1; fa[e->to->ma][0] = node[s].ma; dfs(e->to->ma); } } }
完整代码:
#include <cstdio> const int MAXN = 30007; int n, m, fa[MAXN][30], a[MAXN], ans; /**********************快********************************/ int read() { int x = 0; char ch = getchar(); while (ch < ‘0‘ || ch > ‘9‘) ch = getchar(); while (ch >= ‘0‘ && ch <= ‘9‘) x = x * 10 + ch - ‘0‘, ch = getchar(); return x; } /************************读******************************/ struct Edge; struct Node { Edge *last; int deep, ma; bool vis; } node[MAXN]; struct Edge { Node *from, *to; Edge *next; Edge (Node *from, Node *to) : from(from), to(to), next(from->last) {} }; void addE(int x, int y) { node[x].last = new Edge(node + x, node + y); node[y].last = new Edge(node + y, node + x); } void dfs(int s) { for (int k = 1; k <= 20; k++) // 注意!!!! fa[s][k] = fa[fa[s][k - 1]][k - 1]; for (Edge *e = node[s].last; e; e = e->next) { if (!e->to->deep) { e->to->deep = node[s].deep + 1; fa[e->to->ma][0] = node[s].ma; dfs(e->to->ma); } } } int lca (int x, int y) { if (node[x].deep < node[y].deep) { int t = x; x = y; y = t; } for (int i = 0; i <= 20; i++) { if ((node[x].deep - node[y].deep)>> i & 1) x = fa[x][i]; } if (x == y) return x; for (int i = 20; i >= 0; i--) { if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; } int main() { n = read(); for (int i = 1; i <= n; i++) node[i].ma = i; for (int i = 1, b, c; i < n; i++) { c = read(); b = read(); addE(c, b); } fa[1][0] = 1; node[1].deep = 1; dfs(1); m = read(); for (int i = 1; i <= m; i++) { a[i] = read(); } for (int i = 2; i <= m; i++) { ans += node[a[i]].deep + node[a[i - 1]].deep - 2 * node[lca(a[i - 1], a[i])].deep; } printf("%d\n", ans); return 0; }
以上是关于倍增法求LCA——在线的主要内容,如果未能解决你的问题,请参考以下文章