This is a good write point, that is, the DFS tree, which records the entry and exit locations of each node,
Then find the point corresponding to the minimum value between the last two points that are required, that is, their recent common ancestor.
#include<iostream>#include<cstdio>#include<cstring>#include<map>#include<vector>using namespace std;const int maxn = 111111;struct edge{ int to; int next;}e[maxn*10];int len;int head[maxn];struct Node{ int val; int id;}vis[maxn],dp[maxn][20];int pos[maxn];int cnt;void add(int from, int to){ e[len].to = to; e[len].next = head[from]; head[from] = len++;}void dfs(int x, int val){ vis[cnt].val = val; vis[cnt].id = x; pos[x] = cnt++; for (int i = head[x]; i != -1; i = e[i].next){ int cc = e[i].to; dfs(cc, val + 1); vis[cnt].val = val; vis[cnt].id = x; pos[x] = cnt++; }}void init(int k){ for (int i = 0; i < k; i++) dp[i][0] = vis[i]; for (int j = 1; (1 << j) <= k; j++){ for (int i = 0; i + (1 << j) - 1 < k; i++){ if (dp[i][j - 1].val < dp[i + (1 << (j - 1))][j - 1].val) dp[i][j] = dp[i][j - 1]; else dp[i][j] = dp[i + (1 << (j - 1))][j - 1]; } }}int ask(int l, int r){ int k = 0; while ((1 << (k + 1)) < r - l + 1) k++; if (dp[l][k].val < dp[r - (1 << k) + 1][k].val) return dp[l][k].id; else return dp[r - (1 << k) + 1][k].id;}int main(){ map<string, int> m; map<int, string> m1; string a, b; int n; cin >> n; int sum = 1; len = 0; cnt = 0; memset(head, -1, sizeof(head)); for (int i = 0; i < n; i++){ cin >> a >> b; if (!m.count(a)) m[a] = sum, m1[sum] = a, sum++; if (!m.count(b)) m[b] = sum, m1[sum] = b, sum++; int c = m[a]; int d = m[b]; add(c, d); } dfs(1, 1); init(cnt); int q; cin >> q; while (q--){ cin >> a >> b; int c = pos[m[a]]; int d = pos[m[b]]; if (c > d) swap(c, d); cout << m1[ask(c, d)] << endl; } return 0;}
Hiho16 dynamic LCA