络谷 P3379 [模板] 最近公共祖先 LCA
欧拉序+线段树
int cnt;
int dep[maxn];
int eoo[maxn];
int ooe[maxn << 1];
void dfs_ooe(int u, int f) {
dep[u] = dep[f] + 1;
ooe[++cnt] = u;
eoo[u] = cnt;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (f == v) continue;
dfs_ooe(v, u);
ooe[++cnt] = u;
}
}
int tree[maxn << 3];
void build(int rt, int l, int r) {
if (l == r) {
tree[rt] = ooe[l];
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
tree[rt] = dep[tree[rt << 1]] < dep[tree[rt << 1 | 1]] ? tree[rt << 1] : tree[rt << 1 | 1];
}
int ask(int rt, int l, int r, int tl, int tr) {
if (l == tl && r == tr) return tree[rt];
int mid = (l + r) >> 1;
if (tr <= mid) return ask(rt << 1, l, mid, tl, tr);
if (tl > mid) return ask(rt << 1 | 1, mid + 1, r, tl, tr);
int hl = ask(rt << 1, l, mid, tl, mid);
int hr = ask(rt << 1 | 1, mid + 1, r, mid + 1, tr);
return dep[hl] < dep[hr] ? hl : hr;
}
预处理
dfs_ooe(root, root);
build(1, 1, cnt);
查询
ask(1, 1, cnt, min(eoo[u], eoo[v]), max(eoo[u], eoo[v]))
倍增思想
lli fa[32][maxn];
lli dep[maxn];
void dfs_lca(lli u) {
dep[u] = dep[fa[0][u]] + 1;
for (lli i = 1; (1 << i) <= dep[u]; ++i)
fa[i][u] = fa[i - 1][fa[i - 1][u]];
for (lli i = head[u]; ~i; i = edge[i].nxt) {
lli v = edge[i].v;
if (v == fa[0][u]) continue;
fa[0][v] = u;
dfs_lca(v);
}
}
lli find_lca(lli x, lli y) {
if (x == y) return x;
if (dep[x] > dep[y]) swap(x, y);
for (lli i = 24; i >= 0; --i)
if (dep[x] <= dep[y] - (1 << i))
y = fa[i][y];
if (x == y) return x;
for (lli i = 24; i >= 0; --i)
if (fa[i][x] != fa[i][y])
x = fa[i][x], y = fa[i][y];
return fa[0][x];
}