此问题可以用 LCA 来解决,但是 LCA 的码量大,而且可能容易写挂,~~ 尤其是像我这种蒟蒻~~
如果卡时间的话有可能倍增 / 重链剖分 LCA 都要挂掉,这时候就是 DFS 序发挥作用的时候了。
拿一个计数器。在遍历到每一个节点的时候,我们在进入它的时候记录一下,在离开它的时候也记录一下,在记录完成后就得到了一个树的 DFS 序
代码如下:
/* LOJ10135 https://loj.ac/p/10135 */ #include <iostream> #include <vector> using namespace std; const int maxn = 4e4 + 5; int n, m, root; vector<int> G[maxn]; int ti; int in[maxn], out[maxn]; void dfs(int x) { if(in[x] != 0) return; in[x] = ++ti; for(int to : G[x]) dfs(to); out[x] = ++ti; } int ask(int x, int y) { return in[x] < in[y] && in[y] < out[y] && out[y] < out[x]; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for(int i = 1, u, v; i <= n; i++) { cin >> u >> v; if(v == -1) { root = u; continue; } G[u].push_back(v); G[v].push_back(u); } dfs(root); cin >> m; for(int i = 1, u, v; i <= m; i++) { cin >> u >> v; if(ask(u, v)) cout << 1 << "\n"; else if(ask(v, u)) cout << 2 << "\n"; else cout << 0 << "\n"; } return 0; } //106ms
与倍增 LCA 相比,快了些许
祖孙询问(LOJ10135) https://vjudge.csgrandeur.cn/contest/584212#problem/D */ #include <iostream> #include <vector> using namespace std; const int maxn = 4e4 + 5; const int maxk = 20; int n, root, m; vector<int> G[maxn]; int fa[maxk][maxn]; int depth[maxn]; void dfs(int x, int f) { fa[0][x] = f; depth[x] = depth[f] + 1; for (int i = 1; i < maxk; i++) { fa[i][x] = fa[i - 1][fa[i - 1][x]]; } for (auto to : G[x]) { if (to == f) continue; dfs(to, x); } } int LCA(int x, int y) { if (depth[x] < depth[y]) swap(x, y); for (int i = maxk - 1; i >= 0; i--) { if (depth[fa[i][x]] >= depth[y]) x = fa[i][x]; } if (x == y) return x; for (int i = maxk - 1; i >= 0; i--) { if (fa[i][x] != fa[i][y]) { x = fa[i][x]; y = fa[i][y]; } } return fa[0][x]; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for(int i = 1, u, v; i <= n; i++) { cin >> u >> v; if(v == -1) {root = u; continue;} G[u].push_back(v); G[v].push_back(u); } cin >> m; int x, y; dfs(root, 0); while(m--) { cin >> x >> y; int lca = LCA(x, y); if(lca == x) cout << "1\n"; else if(lca == y) cout << "2\n"; else cout << "0\n"; } } //130ms
因为在使用 DFS 序解决问题时,它的查询是常数时间复杂度,所以说要快很多。
当然,DFS 序也可以用于 LCA 问题中,详见这篇文章。