http://www.spoj.com/problems/COT/ 树上第k小元素
LCA + 可持久化线段树
每个新的版本都是由其父亲版本转化而来。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 6 using namespace std; 7 8 const int maxn = 1e5 + 5; 9 const int maxd = 20; 10 struct Edge{ 11 int v, next; 12 }p[maxn << 1]; 13 int head[maxn], e, d[maxn], f[maxn][maxd]; 14 //LCA 15 void init(){ 16 memset(d, 0, sizeof(d)); 17 memset(f, 0, sizeof(f)); 18 memset(head, -1, sizeof(head)); 19 e = 0; 20 } 21 void addEdge(int u, int v){ 22 p[e].v = v; p[e].next = head[u]; head[u] = e++; 23 swap(u, v); 24 p[e].v = v; p[e].next = head[u]; head[u] = e++; 25 } 26 int lca(int u, int v){ 27 if (d[u] < d[v]) swap(u, v); 28 int k = d[u] - d[v]; 29 for (int i = 0; i < maxd; ++i) 30 if ((1 << i) & k) u = f[u][i]; 31 if (u == v) return u; 32 for (int i = maxd - 1; i >= 0; --i){ 33 if (f[u][i] != f[v][i]){ 34 u = f[u][i]; 35 v = f[v][i]; 36 } 37 } 38 return f[u][0]; 39 } 40 //CMT 41 int ls[maxn * 40], rs[maxn * 40], sum[maxn * 40], T[maxn], tot, rt; 42 int num[maxn], san[maxn], n, m; // 离散化前点数,离散化后点数 43 void init_hash(){ 44 for (int i = 1; i <= n; ++i) san[i] = num[i]; 45 sort(san + 1, san + n + 1); 46 m = unique(san + 1, san + n + 1) - san - 1; 47 } 48 int hash(int x){ 49 return lower_bound(san + 1, san + m + 1, x) - san; 50 } 51 void build(int l, int r, int& rt){ 52 rt = ++ tot; sum[rt] = 0; 53 if (l == r) return; 54 int mid = (l + r) >> 1; 55 build(l, mid, ls[rt]); 56 build(mid + 1, r, rs[rt]); 57 } 58 void update(int last, int pos, int l, int r, int& rt){ 59 rt = ++ tot; 60 ls[rt] = ls[last], rs[rt] = rs[last], sum[rt] = sum[last] + 1; 61 if (l == r) return ; 62 int mid = (l + r) >> 1; 63 if (pos <= mid) update(ls[last], pos, l, mid, ls[rt]); 64 else update(rs[last], pos, mid + 1, r, rs[rt]); 65 } 66 int query(int pos, int left_rt, int right_rt, int lca_rt, int l, int r, int k){ 67 if (l == r) return l; 68 int mid = (l + r) >> 1; 69 int cnt = sum[ls[left_rt]] + sum[ls[right_rt]] - 2 * sum[ls[lca_rt]] + (pos >= l && pos <= mid);//注意lca为跟的时候 70 if (k <= cnt) return query(pos, ls[left_rt], ls[right_rt], ls[lca_rt], l, mid, k); 71 else return query(pos, rs[left_rt], rs[right_rt], rs[lca_rt], mid + 1, r, k - cnt); 72 } 73 //LCA && CMT 74 void dfs(int u, int fa){ 75 f[u][0] = fa;//注意 76 d[u] = d[f[u][0]] + 1; 77 update(T[fa], hash(num[u]), 1, m, T[u]); 78 for (int i = 1; i < maxd; ++i) f[u][i] = f[ f[u][i - 1] ][i - 1]; 79 for (int i = head[u]; ~i; i = p[i].next){ 80 if (p[i].v == fa) continue; 81 dfs(p[i].v, u); 82 } 83 } 84 int main(){ 85 int q, u, v, k; 86 while (scanf("%d%d", &n, &q) == 2){ 87 for (int i = 1; i <= n; ++i) scanf("%d", &num[i]); 88 init(); 89 init_hash(); 90 tot = 0; 91 for (int i = 1; i < n; ++i){ 92 scanf("%d%d", &u, &v); 93 addEdge(u, v); 94 } 95 build(1, m, T[0]); 96 dfs(1, 0); 97 while (q--){ 98 scanf("%d%d%d", &u, &v, &k); 99 printf("%d ",san[query(hash(num[lca(u, v)]), T[u], T[v], T[lca(u, v)],1, m, k)]); 100 } 101 } 102 return 0; 103 }