【BZOJ 2588】Count on a tree

Description

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
 

 

Input

第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
 

Output

 
M行,表示每个询问的答案。

Sample Input

8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output

2
8
9
105
7

HINT

N,M<=100000

暴力自重。。。
 
 
 
分析:
  可持久化线段树,以父亲的版本为基础创建儿子的版本,结合LCA就可以了。(最后多了个\n居然给我格式错误QAQ)
 
代码:
  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 const int maxn = 500000;
  5 const int maxm = 2000000;
  6 
  7 int et[maxn], ep[maxn], last[maxn], en;
  8 int ch[maxm][2], Count[maxm];
  9 int root[maxm], size;
 10 int n, m, u, v, w, lca, ans;
 11 int deep[maxn], fa[maxn][20];
 12 int num[maxn], id[maxn], back[maxn];
 13 
 14 void ins (int a, int b)
 15 {
 16     en++;
 17     ep[en] = last[a];
 18     last[a] = en;
 19     et[en] = b;
 20 }
 21 
 22 #define MID (left + (right - left >> 1))
 23 
 24 
 25 int modify (int left, int right, int pos, int prev)
 26 {
 27     int i = ++size;
 28     if (left < right)
 29     {
 30         int c = pos > MID;
 31         ch[i][!c] = ch[prev][!c];
 32         c ? left = MID + 1 : right = MID;
 33         ch[i][c] = modify (left, right, pos, ch[prev][c]);
 34         Count[i] = Count[ch[i][0]] + Count[ch[i][1]];
 35     }else Count[i] = 1;
 36     return i;
 37 }
 38 
 39 #define LEFTSIZE (Count[ch[l1][0]] + Count[ch[l2][0]] - Count[ch[e1][0]] - Count[ch[e2][0]])
 40 
 41 int query (int left, int right, int e1, int e2, int l1, int l2, int k)
 42 {
 43     if (left == right) return num[id[left]];
 44     int c = k > LEFTSIZE;
 45     c ? left = MID + 1 : right = MID;
 46     return query (left, right, ch[e1][c], ch[e2][c], ch[l1][c], ch[l2][c], c ? k - LEFTSIZE : k);
 47 }
 48 
 49 bool cmp (int a, int b)
 50 {
 51     return num[a] < num[b];
 52 }
 53 
 54 void dfs (int i, int p)
 55 {
 56     deep[i] = deep[p] + 1;
 57     fa[i][0] = p;
 58     for (int b = 0; fa[i][b]; b++)
 59         fa[i][b + 1] = fa[fa[i][b]][b];
 60     root[i] = modify (1, n, back[i], root[p]);
 61     for (int e = last[i]; e; e = ep[e])
 62         if (deep[et[e]] == 0) dfs (et[e], i);
 63 }
 64 
 65 int find (int i, int j)
 66 {
 67     int k, b;
 68     if (deep[i] > deep[j])
 69         i ^= j, j ^= i, i ^= j;
 70     for (k = deep[j] - deep[i], b = 0; k; k >>= 1, b++)
 71         k & 1 ? j = fa[j][b] : 1;
 72     if (i == j) return i;
 73     for (b = 0; fa[i][b] != fa[j][b]; b++);
 74     for (b--; ~b; b--) if (fa[i][b] != fa[j][b]) i = fa[i][b], j = fa[j][b];
 75     return fa[i][0];
 76 }
 77 
 78 int main ()
 79 {
 80     scanf ("%d %d", &n, &m);
 81     for (int i = 1; i <= n; i++)
 82         scanf ("%d", &num[i]), id[i] = i;
 83     std::sort (id + 1, id + n + 1, cmp);
 84     for (int i = 1; i <= n; i++)
 85         back[id[i]] = i;
 86     for (int i = 1; i < n; i++)
 87     {
 88         scanf ("%d %d", &u, &v);
 89         int flag = last[id[1]] > 0;
 90         ins (u, v); ins (v, u);
 91     }
 92     dfs (1, 0);
 93     ans = 0;
 94     for (int i = 0; i < m; i++)
 95     {
 96         scanf ("%d %d %d", &u, &v, &w);
 97         u ^= ans;
 98         lca = find (u, v);
 99         ans = query (1, n, root[fa[lca][0]], root[lca], root[u], root[v], w);
100         if (i) printf ("\n");
101         printf ("%d", ans);
102     }
103 }

 

posted @ 2015-04-03 13:09  Lightning34  阅读(173)  评论(0编辑  收藏  举报