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\n",query(u,v)); 103 } 104 } 105 return 0; 106 }
时间: 2024-10-12 16:01:53