题意:给一棵树,求节点L,L+1,...R的最近公共祖先
思路:先对树dfs一下,从根1出发,经过每条边时记录一下终点和到达这个点的时间截,令r[u]表示到达u这个节点的最早时间截,t[x]表示在时间截x时到达的节点编号,假设对于两个节点u,v,设r[u]<r[v],则在t[r[u]], t[r[u]+1], ..., t[r[v]]这个序列里面一定包含了u和v的LCA。要找出这个LCA也不难,由于这个序列里面的所有节点只有u和v的LCA这个节点的r值最小,于是可以用RMQ求出这个最小r值,然后再利用t数组就得到了LCA的节点编号。对于多个节点的LCA处理方法类似,只需找到多个节点中的r值的最小和最大值,相当于找到了r[u]和r[v],剩下的就与两个点的LCA一样了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #pragma comment(linker, "/STACK:10240000,10240000") #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <algorithm> #include <queue> using namespace std; const int maxn = 3e5 + 7; struct Graph { vector<vector< int > > G; void clear() { G.clear(); } void resize( int n) { G.resize(n + 2); } vector< int > & operator [] ( int x) { return G[x]; } int size() { return G.size(); } void add( int u, int v) { G[u].push_back(v); } }; Graph G; struct ST { struct FI { int a[21]; int & operator [] ( int x) { return a[x]; } }; vector<FI> dp; vector< int > T; void init( int a[], int n, int (*F)( int , int )) { dp.clear(); dp.resize(n); for ( int i = 0; i < n; i ++) dp[i][0] = a[i]; for ( int j = 1; (1 << j) <= n; j ++) { for ( int i = 0; i + (1 << j) - 1 < n; i ++) { dp[i][j] = F(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } T.clear(); T.resize(n); T[1] = 0; for ( int i = 2; i <= n; i ++) { T[i] = T[i - 1]; if ((i & (i - 1)) == 0) T[i] ++; } } int query( int L, int R, int (*F)( int , int )) { int t = T[R - L + 1]; return F(dp[L][t], dp[R - (1 << t) + 1][t]); } }; int fmin( int a, int b) { return a < b? a : b; } int fmax( int a, int b) { return a > b? a : b; } struct LCA { int clock , r[maxn], t[2 * maxn], b[2 * maxn]; bool vis[maxn]; ST st0, st1, st2; void dfs( int rt) { r[rt] = clock ; t[ clock ++] = rt; vis[rt] = true ; int sz = G[rt].size(); for ( int i = 0; i < sz; i ++) { int u = G[rt][i]; if (!vis[u]) { dfs(u); t[ clock ++] = rt; } } } void work() { clock = 0; memset (vis, 0, sizeof (vis)); dfs(1); for ( int i = 0; i < clock ; i ++) b[i] = r[t[i]]; st0.init(b, clock , fmin); st1.init(r + 1, ( clock + 1) >> 1, fmax); st2.init(r + 1, ( clock + 1) >> 1, fmin); } int lca_all( int L, int R) { L --; R --; int lp = st2.query(L, R, fmin), rp = st1.query(L, R, fmax); return t[st0.query(lp, rp, fmin)]; } }; LCA lca; int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); #endif // ONLINE_JUDGE int n, m; while (cin >> n) { G.clear(); G.resize(n); for ( int i = 0; i < n - 1; i ++) { int u, v; scanf ( "%d%d" , &u, &v); G.add(u, v); G.add(v, u); } lca.work(); cin >> m; for ( int i = 0; i < m; i ++) { int L, R; scanf ( "%d%d" , &L, &R); printf ( "%d
" , lca.lca_all(L, R)); } } return 0; } |