樹鏈剖分求lca
阿新 • • 發佈:2022-02-05
題目描述
給一棵有根樹,以及一些詢問,每次詢問樹上的2 個節點A、B,求它們的最近公共祖先.
輸入
第一行一個整數N.接下來N 個數,第i 個數Fi 表示i 的父親是Fi. 若Fi = 0,則i 為樹根.
接下來一個整數M.接下來M 行,每行2 個整數A、B,詢問節點(A xor LastAns)、(Bxor LastAns)的最近公共祖先. 其中LastAns 為上一個詢問的答案,一開始LastAns = 0.
輸出
對每一個詢問輸出相應的答案.
樣例輸入
10
0 1 2 3 2 4 2 5 4 9
10
3 9
2 7
7 8
1 1
0 6
6 11
6 3
10 7
2 15
7 7
樣例輸出
3
1
4
5
2
4
2
5
2
5
#define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxn = 5e5 + 5; vector<int>map[maxn]; int vis[maxn]; int fa[maxn]; int Size[maxn]; int Mainson[maxn]; int depth[maxn]; int root; void DFS1(int v) { vis[v] = 1; Size[v] = 1; for (int i = 0; i < map[v].size(); i++) { int u = map[v][i]; if (!vis[u]) { fa[u] = v; depth[u] = depth[v] + 1; DFS1(u); Size[v] += Size[u]; if (Size[u] > Size[Mainson[v]])Mainson[v] = u; } } } int path[maxn]; void DFS2(int u) { vis[u] = 1; for (int i = 0; i < map[u].size(); i++) { int v = map[u][i]; if (!vis[v]) { if (v == Mainson[u])path[v] = path[u]; else path[v] = v; DFS2(v); } } } int lca(int a, int b) { while (path[a] != path[b]) { if (depth[path[a]] > depth[path[b]])a = fa[path[a]]; else b = fa[path[b]]; } return depth[a] < depth[b] ? a : b; } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { int a; scanf("%d", &a); if (a == 0)root = i; else { map[i].push_back(a); map[a].push_back(i); } } memset(vis, 0, sizeof(vis)); depth[root] = 0; DFS1(root); memset(vis, 0, sizeof(vis)); path[root] = root; DFS2(root); int m;scanf("%d", &m); int lastans = 0; //for (int i = 1; i <= n; i++)printf("%d\n", depth[i]); for (int i = 1; i <= m; i++) { int a, b; scanf("%d %d", &a, &b); int ans = lca(a ^ lastans, b ^ lastans); printf("%d\n", ans); lastans = ans; } }