「学习笔记」树链剖分求LCA
前言
我在洛谷 【模板】最近公共祖先(LCA)上比较了倍增求法与树剖求法
至少评测结果表明树链剖分求lca更快 蒟蒻不会分析时间复杂度
进入正题
lca:树上两个点的最近公共祖先
可以用倍增、树剖、tarjan、dfs 序、以及暴力来求,倍增我有写,tarjan 等会了再说
首先,还是树剖的两个最基本的 dfs,但是相较于一般的维护或修改链上的那种树剖,只是求 lca 的树剖就不用维护那么多信息了 当然了,最最基本的还是要维护的
先上两遍 dfs 的代码:
void dfs(int u, int fat) {
dep[u] = dep[fat] + 1;
fa[u] = fat;
siz[u] = 1;
for(int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == fat) continue;
dfs(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void getpos(int u, int tp) {
top[u] = tp;
if(!son[u]) return ;
getpos(son[u], tp);
for(int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == fa[u] || v == son[u]) continue;
getpos(v, v);
}
}
准备工作做完后,我们开始求 lca
在树剖中,如果两个点不在一条链上,即它们的链顶不同,那就往上跳,直到跳到一条链上
当两个点在一条链上时,深度更浅的点就是 lca
代码:
ll lca(int a, int b) {
while(top[a] != top[b]) {
if(dep[top[a]] < dep[top[b]]) swap(a, b);
a = fa[top[a]];
}
if(dep[a] < dep[b]) return a;
return b;
}
结束
朝气蓬勃 后生可畏