这个博客写得好
1 #include <stdio.h>
2 #include <vector>
3 #include <string.h>
4 using namespace std;
5 const int N = 100000;
6
7 /*
8 lca 转RMQ
9
10 询问u和v的lca
11 我们保存树的遍历序列,那么只要在序列中找到第一次出现u和第一次出现v的位置
12 然后RMQ该区间深度最小的那个点就是u和v的lca了
13
14 那么要保存每个点首次出现的位置
15 还要保存遍历序列的dep序列,然后RMQ dep序列得到哪一位置的dep最小
16 然后映射为结点
17 */
18
19 vector<int> g[N];
20 int total;
21 int id[N];
22 int dep[N];
23 int ref[N];
24 int dp[N][30];
25 int pos[N][30];
26 void dfs(int u, int fa, int d)
27 {
28 id[u] = ++total;
29 dep[total] = d;//去
30 ref[total] = u;
31 for(int i=0;i<g[u].size(); ++i)
32 {
33 int v = g[u][i];
34 if(v==fa)continue;
35 dfs(v,u,d+1);
36 dep[++total] = d;//回来
37 ref[total] = u;
38 }
39
40 }
41
42 void init()
43 {
44 int n = total;
45 for(int i=1;i<=n;++i)
46 dp[i][0] = i;
47
48
49 for(int j=1;(1<<j)<=n;++j)
50 {
51 for(int i=1;i+(1<<j)-1<=n;++i)
52 {
53 int a = dp[i][j-1];
54 int b = dp[i+(1<<(j-1))][j-1];
55 if(dep[a] < dep[b])
56 dp[i][j] = a;
57 else
58 dp[i][j] = b;
59 }
60 }
61 }
62 int query(int u, int v)
63 {
64 if(id[u] > id[v])
65 swap(u,v);
66 int L = id[u];
67 int R = id[v];
68 int k = 0;
69 while(1<<(k+1)<=R-L+1)k++;
70 int a = dp[L][k];
71 int b = dp[R-(1<<k)+1][k];
72 if(R[a]<R[b])
73 {
74 return ref[a];
75 }
76 else
77 return ref[b];
78 }
79 int main()
80 {
81 int n;
82 while(scanf("%d",&n)!=EOF)
83 {
84 for(int i=1;i<=n;++i)
85 g[i].clear();
86 int u,v;
87 for(int i=1;i<n;++i)
88 {
89 scanf("%d%d",&u,&v);
90 g[u].push_back(v);
91 g[v].push_back(u);
92 }
93 total = 0;
94 dep[1] = 1;
95 dfs(1,-1,1);
96 init();
97 int m;
98 scanf("%d",&m);
99 while(m--)
100 {
101 scanf("%d%d",&u,&v);
102 printf("%d
",query(u,v));
103 }
104 }
105 return 0;
106 }