好久没有写博客了,联赛前一天来写一点关于LCA的各种模板
极力推荐第四种方法
1.Sparce_Table 算法
把树按照DFS序重新编号并求出DFS序列后,利用序列中两点编号之间的最小值即为LCA的性质,通过RMQ求解。
代码如下:
/*
ID: Sunshine_cfbsl
LANG: C++
PROG: LCA
*/
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN = 500010;
int n, m, s, fp[MAXN], id[MAXN], pn, an, dp[MAXN*2][21];
int Begin[MAXN], to[MAXN*2], Next[MAXN*2], e;
inline 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;
}
inline void Add(int u, int v) {
to[++e] = v;
Next[e] = Begin[u];
Begin[u] = e;
}
void dfs(int u, int f) {
int i, c;
id[c = ++pn] = u;
dp[fp[u] = ++an][0] = c;
for(i = Begin[u]; i; i = Next[i]) {
if(to[i] == f) continue;
dfs(to[i], u);
dp[++an][0] = c;
}
}
void Sparse_Table() {
int i, j;
for(j = 1; (1<<j) <= an; j++)
for(i = 1; i+(1<<j)-1 <= an; i++)
dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
}
inline int LCA(int l, int r) {
int i, k = (int) (log(r-l+1)/log(2));
return id[min(dp[l][k], dp[r-(1<<k)+1][k])];
}
int main() {
int i, u, v;
n = read();
m = read();
s = read();
for(i = 1; i < n; i++) {
u = read();
v = read();
Add(u, v);
Add(v, u);
}
dfs(s, -1);
Sparse_Table();
for(i = 1; i <= m; i++) {
u = read();
v = read();
if(fp[u] > fp[v]) swap(u, v);
printf("%d\n", LCA(fp[u], fp[v]));
}
return 0;
}
如果这里用链式前向星存树,它比邻接表要快一些。
时间复杂度 O(n+nlo