倍增lca的另类做法(以空间换取小常数)
陈锋老师讲到的倍增lca的另类做法。
众所周知,可以利用利用dfs序判断一个点y是否在点x的子树中(不再赘述)。
于是在寻找x和y的lca的时候,只需要让深度小的那个点(y)往上倍增爬,直到y的父亲是x的祖先。
这个原理上比传统算法快了一倍,但是占用了较多的内存。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <iomanip> #include <cmath> #include <queue> #include <map> using namespace std; #define reg register #define LL long long inline LL read() { LL res=0;char ch=getchar();bool fu=0; while(!isdigit(ch)) fu|=(ch=='-'), ch=getchar(); while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return fu ? -res : res; } #define mkp make_pair #define pii pair<int, int> namespace BriMon { #define N 500005 int n, m, root; struct edge { int nxt, to; }ed[N<<1]; int head[N], cnt; inline void add(int x, int y) { ed[++cnt] = (edge){head[x], y}; head[x] = cnt; } int fa[N][21], dep[N]; int in[N], out[N], dfsc; bool isancestor(int x, int y) //x是不是y的祖先 { return (in[x] <= in[y]) and (out[x] >= out[y]); } inline int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); if (isancestor(y, x)) return y; for (reg int i = 20 ; i >= 0 ; i --) if (fa[y][i] and !isancestor(fa[y][i], x)) y = fa[y][i]; return fa[y][0]; } void dfs(int x) { in[x] = ++dfsc; for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (dep[to]) continue; dep[to] = dep[x] + 1; fa[to][0] = x; for (reg int j = 1 ; j <= 20 ; j ++) fa[to][j] = fa[fa[to][j-1]][j - 1]; dfs(to); } out[x] = ++dfsc; } signed main() { n = read(), m = read(), root = read(); for (reg int i = 1 ; i < n ; i ++) { int x = read(), y = read(); add(x, y), add(y, x); } dep[root] = 1; dfs(root); while(m--) printf("%d\n", lca(read(), read())); return 0; } } signed main() { BriMon :: main(); return 0; }