首页 > 其他 > 详细

【bzoj2588】Spoj 10628. Count on a tree

时间:2017-01-17 11:41:10      阅读:226      评论:0      收藏:0      [点我收藏+]

题目描述

 

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

 

输入

 

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

 

输出

 

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

 

样例输入

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

样例输出

2
8
9
105
7


题解

主席树(不需要树剖)+最近公共祖先(这里使用树剖)

这道题不能树剖,否则没法做。

需要明确主席树的原理:线段树相加减。

那么A到B的路径就是 A到根的路径+B到根的路径-最近公共祖先到根的路径-最近公共祖先的父亲到根的路径。

可以直接在树上建立主席树,注意每棵树是从它父亲的树推来的。

然后查询即可。

注意最后一行千万不能有换行,否则无限PE!

  1 #include <cstdio>
  2 #include <algorithm>
  3 #define N 100001
  4 using namespace std;
  5 struct data
  6 {
  7     int num , rank;
  8 }a[N];
  9 int root[N] , lp[N << 5] , rp[N << 5] , sum[N << 5] , val[N] , top , tot;
 10 int head[N] , to[N << 1] , next[N << 1] , cnt , fa[N] , bl[N] , deep[N] , si[N] , q[N] , tail;
 11 bool cmp1(data a , data b)
 12 {
 13     return a.num < b.num;
 14 }
 15 bool cmp2(data a , data b)
 16 {
 17     return a.rank < b.rank;
 18 }
 19 void add(int x , int y)
 20 {
 21     to[++cnt] = y;
 22     next[cnt] = head[x];
 23     head[x] = cnt;
 24 }
 25 void dfs1(int x)
 26 {
 27     int i;
 28     si[x] = 1;
 29     for(i = head[x] ; i ; i = next[i])
 30     {
 31         if(to[i] != fa[x])
 32         {
 33             fa[to[i]] = x;
 34             deep[to[i]] = deep[x] + 1;
 35             dfs1(to[i]);
 36             si[x] += si[to[i]];
 37         }
 38     }
 39 }
 40 void dfs2(int x , int c)
 41 {
 42     int i , k = 0;
 43     bl[x] = c;
 44     q[++tail] = x;
 45     for(i = head[x] ; i ; i = next[i])
 46         if(to[i] != fa[x] && si[to[i]] > si[k])
 47             k = to[i];
 48     if(k)
 49     {
 50         dfs2(k , c);
 51         for(i = head[x] ; i ; i = next[i])
 52             if(to[i] != fa[x] && to[i] != k)
 53                 dfs2(to[i] , to[i]);
 54     }
 55 }
 56 int getlca(int x , int y)
 57 {
 58     while(bl[x] != bl[y])
 59     {
 60         if(deep[bl[x]] < deep[bl[y]])
 61             swap(x , y);
 62         x = fa[bl[x]];
 63     }
 64     if(deep[x] < deep[y]) return x;
 65     return y;
 66 }
 67 void pushup(int x)
 68 {
 69     sum[x] = sum[lp[x]] + sum[rp[x]];
 70 }
 71 void ins(int x , int &y , int l , int r , int p)
 72 {
 73     y = ++tot;
 74     if(l == r)
 75     {
 76         sum[y] = sum[x] + 1;
 77         return;
 78     }
 79     int mid = (l + r) >> 1;
 80     if(p <= mid) rp[y] = rp[x] , ins(lp[x] , lp[y] , l , mid , p);
 81     else lp[y] = lp[x] , ins(rp[x] , rp[y] , mid + 1 , r , p);
 82     pushup(y);
 83 }
 84 int query(int a , int b , int c , int d , int l , int r , int p)
 85 {
 86     if(l == r) return val[l];
 87     int mid = (l + r) >> 1;
 88     if(sum[lp[a]] + sum[lp[b]] - sum[lp[c]] - sum[lp[d]] >= p) return query(lp[a] , lp[b] , lp[c] , lp[d] , l , mid , p);
 89     else return query(rp[a] , rp[b] , rp[c] , rp[d] , mid + 1 , r , p - sum[lp[a]] - sum[lp[b]] + sum[lp[c]] + sum[lp[d]]);
 90 }
 91 int main()
 92 {
 93     int n , m , i , x , y , z , f , last = 0;
 94     scanf("%d%d" , &n , &m);
 95     for(i = 1 ; i <= n ; i ++ )
 96     {
 97         scanf("%d" , &a[i].num);
 98         a[i].rank = i;
 99     }
100     sort(a + 1 , a + n + 1 , cmp1);
101     val[0] = 0x80000000;
102     for(i = 1 ; i <= n ; i ++ )
103     {
104         if(a[i].num != val[top]) val[++top] = a[i].num;
105         a[i].num = top;
106     }
107     sort(a + 1 , a + n + 1 , cmp2);
108     for(i = 1 ; i < n ; i ++ )
109     {
110         scanf("%d%d" , &x , &y);
111         add(x , y);
112         add(y , x);
113     }
114     dfs1(1);
115     dfs2(1 , 1);
116     for(i = 1 ; i <= tail ; i ++ )
117         ins(root[fa[q[i]]] , root[q[i]] , 1 , top , a[q[i]].num);
118     while(m -- )
119     {
120         scanf("%d%d%d" , &x , &y , &z);
121         x ^= last;
122         f = getlca(x , y);
123         last = query(root[x] , root[y] , root[f] , root[fa[f]] , 1 , top , z);
124         printf("%d" , last);
125         if(m) printf("\n");
126     }
127     return 0;
128 }

 

【bzoj2588】Spoj 10628. Count on a tree

原文:http://www.cnblogs.com/GXZlegend/p/6292371.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!