题意:N个点的有向树, Q次询问, 每次询问区间[L, R]内所有点的LCA。
大致做法:线段树每个点保存它的孩子的LCA值, 对于每一次询问只需要 在线段树查询即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int MAXN = 3e5+10; 4 struct Edge{ 5 int to, next; 6 }e[MAXN << 1]; 7 int head[MAXN], tot_edge; 8 void Add_Edge (int x, int y){ 9 e[tot_edge].to = y; 10 e[tot_edge].next = head[x]; 11 head[x] = tot_edge++; 12 } 13 int n, q, MAX_LOG_V; 14 bool vis[MAXN]; 15 void init (){ 16 MAX_LOG_V = 20; 17 tot_edge = 0; 18 memset(head, -1, sizeof (head)); 19 memset(vis, false, sizeof (vis)); 20 } 21 int dep[MAXN], pa[25][MAXN]; 22 void DFS (int r, int pre, int d){ // DFS 或 BFS都可以, G++下BFS 23 dep[r] = d; 24 pa[0][r] = pre; 25 for (int i = head[r]; ~i; i = e[i].next){ 26 int u = e[i].to; 27 if (pre != u){ 28 DFS(u, r, d+1); 29 } 30 } 31 } 32 void BFS (int r, int pre, int d){ 33 dep[r] = d; 34 pa[0][r] = pre; 35 queue <int>Q; 36 Q.push(r); 37 vis[r] = true; 38 while (!Q.empty()){ 39 int u = Q.front(); 40 Q.pop(); 41 for (int i = head[u]; ~i; i = e[i].next){ 42 int v = e[i].to; 43 if (!vis[v]){ 44 dep[v] = dep[u] + 1; 45 pa[0][v] = u; 46 Q.push(v); 47 vis[v] = true; 48 } 49 } 50 } 51 } 52 void pre_solve (){ 53 BFS(1, -1, 0); 54 for (int k = 0; k + 1 < MAX_LOG_V; k++){ 55 for (int v = 1; v <= n; v++){ 56 if (pa[k][v] < 0){ 57 pa[k+1][v] = -1; 58 }else{ 59 pa[k+1][v] = pa[k][pa[k][v]]; 60 } 61 } 62 } 63 } 64 int LCA (int u, int v){ 65 if (dep[u] > dep[v]){ 66 swap(u, v); 67 } 68 for (int k = 0; k < MAX_LOG_V; k++){ 69 if ((dep[v] - dep[u]) >> k & 1){ 70 v = pa[k][v]; 71 } 72 } 73 if (u == v){ 74 return u; 75 } 76 for (int k = MAX_LOG_V-1; k >= 0; k--){ 77 if (pa[k][u] != pa[k][v]){ 78 u = pa[k][u]; 79 v = pa[k][v]; 80 } 81 } 82 return pa[0][u]; 83 } 84 int seg[MAXN << 2]; 85 void push_up(int pos){ 86 seg[pos] = LCA(seg[pos<<1], seg[pos<<1|1]); 87 } 88 void build (int l, int r, int pos){ 89 if (l == r){ 90 seg[pos] = l; 91 return ; 92 } 93 int mid = (l + r) >> 1; 94 build(l, mid, pos<<1); 95 build(mid+1, r, pos<<1|1); 96 push_up(pos); 97 } 98 int query (int l, int r, int pos, int ua, int ub){ 99 if (ua <= l && ub >= r){ 100 return seg[pos]; 101 } 102 int mid = (l + r) >> 1; 103 int t1 = -1, t2 = -1; 104 if (ua <= mid){ 105 t1 = query(l, mid, pos<<1, ua, ub); 106 } 107 if (ub > mid){ 108 t2 = query(mid+1, r, pos<<1|1, ua, ub); 109 } 110 if (t1 == -1 || t2 == -1){ 111 return max(t1, t2); 112 }else{ 113 return LCA(t1, t2); 114 } 115 } 116 int main() 117 { 118 #ifndef ONLINE_JUDGE 119 freopen("in.txt","r",stdin); 120 #endif 121 while (~ scanf ("%d", &n)){ 122 init(); 123 for (int i = 0; i < n-1; i++){ 124 int u, v; 125 scanf ("%d%d", &u, &v); 126 Add_Edge(u, v); 127 Add_Edge(v, u); 128 } 129 pre_solve(); 130 build(1, n, 1); 131 scanf ("%d", &q); 132 for (int i = 0; i < q; i++){ 133 int ua, ub; 134 scanf ("%d%d", &ua, &ub); 135 printf("%d\n", query(1, n, 1, ua, ub)); 136 } 137 } 138 return 0; 139 }
时间: 2024-10-12 05:14:22