LCA 的一些扩展算法
\(LCA\) 的一些扩展问题
一. 暴力
一步一步跳
算法:
(1) 求出每个点的深度
(2) 判断两个点是否重合,若是则该点就是 \(LCA\)
(3) 否则,选择深度大的点移动到它父亲
最坏情况下复杂度\(O(n)\)
随机情况下,树高度期望是\(O(n~log~n)\),可以放心食用
实现简单,是理想的对拍程序
只需要知道每个节点的父亲和深度,允许树动态改变
二. 倍增
不讲了
三. \(LCA\) 转化为 \(rmq\) 问题
\(dfs\) 遍历所有结点,建立三个数组
\(ver[i]\) : 表示 \(dfs\) 第 \(i\) 个访问的节点(dfs序)
\(dep[i]\) : 表示 \(ver[i]\) 的层数
\(first[i]\) : 表示 \(ver[i]\) 第一次出现的下标
查找 \(x,y\) 的最近公共祖先 就相当于在 \([first[u],first[v]]\) 区间中找 \(dep\) 最小的
具体见代码
void dfs(int u, int Dep, int f) {
fa[u] = f ;
vis[u] = 1 ; node[++tot] = u ;
first[u] = tot ; dep[tot] = Dep ;
rep(i, 0, siz(e[u]) - 1) {
int v = e[u][i] ;
if (vis[v]) continue ;
dfs(v, Dep + 1, u) ;
node[++tot] = u ;
dep[tot] = Dep ;
}
}
void st(int n) {
int k = (int) (log(double(n)) / log(2.0)) ;
rep(i, 1, n) dp[i][0] = i ;
rep(j, 1, k)
rep(i, 1, n + 1 - Pw[j]) {
int a = dp[i][j - 1] ;
int b = dp[i + Pw[j - 1]][j - 1] ;
if (dep[a] < dep[b]) dp[i][j] = a ;
else dp[i][j] = b ;
}
}
int ask(int x, int y) {
int k = (int) (log(double(y - x + 1)) / log(2.0)) ;
int a = dp[x][k] ;
int b = dp[y - Pw[k] + 1][k] ;
if (dep[a] < dep[b]) return a ;
return b ;
}
int lca(int u, int v) {
int x = first[u], y = first[v] ;
if (x > y) swap(x, y);
int s = ask(x, y);
return node[s] ;
}
四. \(Tarjan\)
Tarjan是离线算法,复杂度 \(O(n)\)
首先把所有的询问离线
之后遍历所有点,对于一个点 \(u\)
他的儿子 \(v\) 如果没有遍历过那么就把 \(u,v\) 合并
然后对于 \(u\) 的所有询问,如果可以回答的,答案就是对应 \(v\) 的并查集的根
Luogu 3379 模板题
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
const int N = 500010 ;
int n, m, Rt, qid ;
int ans[N], fa[N], vis[N] ;
bool flg[N] ;
struct query {
int t, qid ;
} ;
vector <int> e[N] ;
vector <query> q[N] ;
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]) ;
}
void dfs(int u, int ft) {
rep(i, 0, siz(e[u]) - 1) {
int v = e[u][i] ;
if (v == ft || vis[v]) continue ;
dfs(v, u) ;
fa[find(v)] = find(u) ;
vis[v] = 1 ;
}
rep(i, 0, siz(q[u]) - 1)
if (!flg[q[u][i].qid] && vis[q[u][i].t]) {
ans[q[u][i].qid] = find(q[u][i].t) ;
flg[q[u][i].qid] = 1 ;
}
}
signed main() {
scanf("%d%d%d", &n, &m, &Rt) ;
rep(i, 1, n) fa[i] = i ;
rep(i, 1, n - 1) {
int x, y ; scanf("%d%d", &x, &y) ;
e[x].pb(y) ; e[y].pb(x) ;
}
rep(i, 1, m) {
int x, y ; scanf("%d%d", &x, &y) ;
q[x].pb((query){y, i}) ;
q[y].pb((query){x, i}) ;
}
dfs(Rt, 0) ;
rep(i, 1, m) printf("%d\n", ans[i]) ;
return 0 ;
}
加油ヾ(◍°∇°◍)ノ゙