图论-LCA的 3 种求法:离线Tarjan, 树上倍增, 欧拉序+RMQ

1. 树上倍增

f[i][k] 表示节点 i 向上第 2个节点。mx 是树的最大深度。

预处理:

先 DFS 得到 f[i][0] ,然后:

1 for (k = 1; k <= mx; ++k)
2     for (i = 1; i <= N; ++i)
3         dad[i][k] = dad[dad[i][k-1]][k-1];

求 LCA :

 1 int LCA(int t1, int t2)
 2 {
 3     
 4     int i;
 5     ans = 0;
 6     if (depth[t1] < depth[t2]) swap(t1, t2);
 7     int tmp = depth[t1] - depth[t2];
 8     for (i = 0; i <= mx; ++i)
 9         if ((tmp>>i) & 1)
10             ans += 1<<i, t1 = dad[t1][i];
11     if (t1 == t2) return t1;
12     for (i = mx; i >= 0; --i)
13         if (dad[t1][i] != dad[t2][i])
14             t1 = dad[t1][i], t2 = dad[t2][i];
15     return dad[t1][0];
16 }

2. 欧拉序+RMQ

DFS 得到树的欧拉序列,记录每个点在欧拉序列中第一次出现的位置 pos[i] 。

x, y 的 LCA 即为欧拉序列的 [pos[x], pos[y]] 区间的最小值。预处理欧拉序列,查询最小值的操作用 RMQ 实现。这样查询的复杂度是 O(1) 的,比法 1 树上倍增的 O(log N) 优秀。

3. 离线 Tarjan

猜你喜欢

转载自www.cnblogs.com/ghcred/p/9301587.html
今日推荐