On this page
article
LCA com binary lifting
Sobre
Assume que um vertice eh ancestral dele mesmo, ou seja,
se a eh ancestral de b, lca(a, b) = a
MAX2 = ceil(log(MAX))
Complexidades:
build - O(n log(n))
lca - O(log(n))
Link original: lcaComBinaryLifting.cpp
Código
vector<vector<int> > g(MAX);
int n, p;
int pai[MAX2][MAX];
int in[MAX], out[MAX];
void dfs(int k) {
in[k] = p++;
for (int i = 0; i < (int) g[k].size(); i++)
if (in[g[k][i]] == -1) {
pai[0][g[k][i]] = k;
dfs(g[k][i]);
}
out[k] = p++;
}
void build(int raiz) {
for (int i = 0; i < n; i++) pai[0][i] = i;
p = 0, memset(in, -1, sizeof in);
dfs(raiz);
// pd dos pais
for (int k = 1; k < MAX2; k++) for (int i = 0; i < n; i++)
pai[k][i] = pai[k - 1][pai[k - 1][i]];
}
bool anc(int a, int b) { // se a eh ancestral de b
return in[a] <= in[b] and out[a] >= out[b];
}
int lca(int a, int b) {
if (anc(a, b)) return a;
if (anc(b, a)) return b;
// sobe a
for (int k = MAX2 - 1; k >= 0; k--)
if (!anc(pai[k][a], b)) a = pai[k][a];
return pai[0][a];
}
// Alternativamente:
// 'binary lifting' gastando O(n) de memoria
// Da pra add folhas e fazer queries online
// 3 vezes o tempo do binary lifting normal
//
// build - O(n)
// kth, lca, dist - O(log(n))
int d[MAX], p[MAX], pp[MAX];
void set_root(int i) { p[i] = pp[i] = i, d[i] = 0; }
void add_leaf(int i, int u) {
p[i] = u, d[i] = d[u]+1;
pp[i] = 2*d[pp[u]] == d[pp[pp[u]]]+d[u] ? pp[pp[u]] : u;
}
int kth(int i, int k) {
int dd = max(0, d[i]-k);
while (d[i] > dd) i = d[pp[i]] >= dd ? pp[i] : p[i];
return i;
}
int lca(int a, int b) {
if (d[a] < d[b]) swap(a, b);
while (d[a] > d[b]) a = d[pp[a]] >= d[b] ? pp[a] : p[a];
while (a != b) {
if (pp[a] != pp[b]) a = pp[a], b = pp[b];
else a = p[a], b = p[b];
}
return a;
}
int dist(int a, int b) { return d[a]+d[b]-2*d[lca(a,b)]; }
vector<int> g[MAX];
void build(int i, int pai=-1) {
if (pai == -1) set_root(i);
for (int j : g[i]) if (j != pai) {
add_leaf(j, i);
build(j, i);
}
}