spoj 10628

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\n",san[query(hash(num[lca(u, v)]), T[u], T[v], T[lca(u, v)],1, m, k)]);
100         }
101     }
102     return 0;
103 }

 

posted @ 2013-09-24 10:51  Missa  阅读(591)  评论(0编辑  收藏  举报