由于没有大量时间写详细的博客,只作为学习时的思路统计,便于复习,别学完就忘了
倍增求LCA
建立祖先关系
parents[u][0] 表示 u 的
2
0
2^0
20 的祖先,即 u 的祖先
parents[u][1] 表示 u 的
2
1
2^1
21 的祖先,即父亲的父亲
parents[u][x] 表示 u 的
2
x
2^x
2x 的祖先,通过 2 的倍数做标记
form[u]表示当前点的祖先
获取各个节点的深度O(n)
BFS或者DFS即可
完善parents数组O(n*logn)
根据倍增的转移方程,
f
(
i
,
j
)
f(i,j)
f(i,j) 表示区间
[
i
,
i
+
2
j
−
1
]
[i,i+2^{j}-1]
[i,i+2j−1] 的答案
f
(
i
,
j
)
=
关系
(
f
(
i
,
j
−
1
)
,
f
(
i
+
2
j
−
1
,
j
−
1
)
)
f(i,j)=关系(f(i,j-1),f(i+2^{j-1},j-1))
f(i,j)=关系(f(i,j−1),f(i+2j−1,j−1))
p a r e n t s [ i ] [ j ] = p a r e n t s [ p a r e n t s [ i ] [ j − 1 ] ] [ j − 1 ] parents[i][j] = parents[parents[i][j-1]][j-1] parents[i][j]=parents[parents[i][j−1]][j−1]
查询LCA(logu)
- 取深度较深的节点为 u,获得 u 能往上找的 2 x 2^x 2x的最大跨度
- 遍历跨度,从大到小,找到与 v 相同深度的祖先
- u 与 v 一起往上找,遍历跨度,从大到小,直到找到LCA。
代码
from https://blog.csdn.net/wjh2622075127/article/details/81060586
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 10005;
int parents[maxn][20], depth[maxn];
int n, from[maxn], root = -1;
vector<int> G[maxn];
void init()
{
memset(parents, -1, sizeof(parents));
memset(from, -1, sizeof(from));
memset(depth, -1, sizeof(depth));
}
void getData()
{
cin >> n;
int u, v;
for (int i = 1; i < n; ++i) {
cin >> u >> v;
G[u].push_back(v);
parents[v][0] = u;
from[v] = 1;
}
for (int i = 1; i <= n; ++i) {
if (from[i] == -1) root = i;
}
}
void getDepth_dfs(int u)
{
int len = G[u].size();
for (int i = 0; i < len; ++i) {
int v = G[u][i];
depth[v] = depth[u] + 1;
getDepth_dfs(v);
}
}
void getDepth_bfs(int u)
{
queue<int> Q;
Q.push(u);
while (!Q.empty()) {
int v = Q.front();
Q.pop();
for (int i = 0; i < G[v].size(); ++i) {
depth[G[v][i]] = depth[v] + 1;
Q.push(G[v][i]);
}
}
}
void getParents()
{
for (int up = 1; (1 << up) <= n; ++up) {
for (int i = 1; i <= n; ++i) {
parents[i][up] = parents[parents[i][up - 1]][up - 1];
}
}
}
int Lca(int u, int v)
{
if (depth[u] < depth[v]) swap(u, v);
int i = -1, j;
while ((1 << (i + 1)) <= depth[u]) ++i;
for (j = i; j >= 0; --j) {
if (depth[u] - (1 << j) >= depth[v]) {
u = parents[u][j];
}
}
if (u == v) return u;
for (j = i; j >= 0; --j) {
if (parents[u][j] != parents[v][j]) {
u = parents[u][j];
v = parents[v][j];
}
}
return parents[u][0];
}
void questions()
{
int q, u, v;
cin >> q;
for (int i = 0; i < q; ++i) {
cin >> u >> v;
int ans = Lca(u, v);
cout << ans << endl;
//cout << u << " 和 " << v << " 的最近公共祖先(LCA)是: " << ans << endl;
}
}
int main()
{
init();
getData();
depth[root] = 1;
getDepth_dfs(root);
//getDepth_bfs(root);
getParents();
questions();
}
/*
9
1 2
1 3
1 4
2 5
2 6
3 7
6 8
7 9
5
1 3
5 6
8 9
8 4
5 8
*/
求后缀数组
后缀数组,sa[i] 表示排名第 i 小的后缀
倍增,求LCA (具体知识点见上文
基数排序
DC3
后缀数组区间可加性