图论-LCA的3种求法:离线Tarjan、树上倍增、 欧拉序+RMQ
1. 树上倍增
f[i][k] 表示节点 i 向上第 2k 个节点。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