SPOJ QTREE 系列解题报告

题目一 : SPOJ 375 Query On a Tree

http://www.spoj.com/problems/QTREE/

给一个树,求a,b路径上最大边权,或者修改a,b边权为t。

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 const int maxn = 200000 + 5;
  9 
 10 int N,pos=0;
 11 char ss[50];
 12 
 13 struct SegmentTree{
 14     int l,r,flag;
 15     int maxv,minv;
 16 }Node[maxn * 10];
 17 
 18 int e[maxn][4];
 19 int size[maxn],dep[maxn],top[maxn],son[maxn];
 20 int fa[maxn],Segnum[maxn],Treenum[maxn];
 21 
 22 int tot = 0;
 23 int first[maxn],next[maxn*2];
 24 int u[maxn*2],v[maxn*2];
 25 
 26 void clear();
 27 void change(int&,int&);
 28 void Add(int,int);
 29 void dfs_1(int,int,int);
 30 void dfs_2(int,int);
 31 void build(int,int,int);
 32 void update(int,int,int,int);
 33 int query(int,int,int);
 34 int find_max(int,int);
 35 void rever(int,int,int);
 36 void get_rever(int,int);
 37 void pushdown(int);
 38 void pushup(int);
 39 
 40 int main(){
 41     int tcase;
 42     scanf("%d",&tcase);
 43     while(tcase --){
 44         clear();
 45         int x,y,z;
 46         scanf("%d",&N);
 47         for(int i = 1;i < N;++ i){
 48             scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
 49             Add(e[i][0],e[i][1]);
 50             Add(e[i][1],e[i][0]);
 51         }    
 52         
 53         dfs_1(1,0,1);
 54         dfs_2(1,1);
 55         build(1,1,N);    
 56         for(int i = 1;i < N;++ i){
 57             if(dep[e[i][0]] > dep[e[i][1]])
 58                 swap(e[i][0],e[i][1]);
 59             update(1,Segnum[e[i][1]],Segnum[e[i][1]],e[i][2]);    
 60         }
 61         while(1){
 62             scanf("%s",ss);
 63             if(ss[0] == 'D')
 64                 break;
 65             scanf("%d%d",&x,&y);
 66             if(ss[0] == 'C'){
 67                 update(1,Segnum[e[x][1]],Segnum[e[x][1]],y);
 68             }
 69             else if(ss[0] == 'Q'){
 70                 printf("%d
",find_max(x,y));
 71             }
 72             else if(ss[0] == 'N'){
 73                 get_rever(x,y);
 74             }
 75         }
 76     } 
 77     return 0;
 78 }
 79 
 80 void clear(){
 81     pos = 0;tot = 0;
 82     memset(son,0,sizeof son);
 83     memset(first,0,sizeof first);
 84 }
 85 void Add(int s,int t){
 86     ++ tot;
 87     u[tot] = s;v[tot] = t;
 88     next[tot] = first[u[tot]];
 89     first[u[tot]] = tot;
 90 }
 91 void dfs_1(int now,int f,int depth){
 92     size[now] = 1;
 93     fa[now] = f;
 94     dep[now] = depth;
 95     
 96     for(int i = first[now];i;i = next[i]){
 97         if(v[i] != f){
 98             dfs_1(v[i],now,depth + 1);
 99             size[now] += size[v[i]];
100             if(!son[now] || size[v[i]] > size[son[now]])
101                 son[now] = v[i];
102         }
103     }
104     return;
105 }
106 
107 void dfs_2(int now,int ances){
108     top[now] = ances;
109     Segnum[now] = ++ pos;
110     Treenum[Segnum[now]] = now;
111     
112     if(!son[now])return;
113     dfs_2(son[now],ances);
114     
115     for(int i = first[now];i;i = next[i]){
116         if(v[i] != son[now] && v[i] != fa[now]){
117             dfs_2(v[i],v[i]);
118         }
119     }
120     return;
121 }
122 
123 void build(int o,int l,int r){
124     Node[o].l = l;
125     Node[o].r = r;
126     Node[o].minv = Node[o].maxv = 0;
127     Node[o].flag = 0;
128     if(l == r)
129         return;
130     int Mid = (l + r) >> 1;
131     build(o<<1,l,Mid);
132     build(o<<1|1,Mid+1,r);
133 }
134 
135 void update(int o,int l,int r,int v){
136     if(Node[o].l == l && Node[o].r == r){
137         Node[o].minv = Node[o].maxv = v;
138         Node[o].flag = 0;
139         return;
140     }
141     int Mid = (Node[o].l + Node[o].r) >> 1;
142     pushdown(o);
143     if(r <= Mid)
144         update(o<<1,l,r,v);
145     else if(l > Mid)
146         update(o<<1|1,l,r,v);
147     pushup(o);
148 }
149 void pushdown(int o){
150     if(Node[o].l == Node[o].r)
151         return;
152     int lc = o << 1,rc = o << 1 | 1;
153     if(Node[o].flag){
154         Node[o].flag = 0;
155         Node[lc].flag ^= 1;
156         Node[rc].flag ^= 1;
157         change(Node[rc].minv,Node[rc].maxv);
158         change(Node[lc].maxv,Node[lc].minv);
159     }
160 }
161 void pushup(int o){
162     int lc = o << 1,rc = o << 1 | 1;
163     Node[o].maxv = max(Node[lc].maxv,Node[rc].maxv);
164     Node[o].minv = min(Node[lc].minv,Node[rc].minv);
165 }
166 
167 int query(int o,int l,int r){
168     if(Node[o].l == l && Node[o].r == r){
169         return Node[o].maxv;
170     }
171     int Mid = (Node[o].l + Node[o].r) >> 1;
172     pushdown(o);
173     if(r <= Mid)
174         return query(o<<1,l,r);
175     else if(l > Mid)
176         return query(o<<1|1,l,r);
177     else
178         return max(query(o<<1,l,Mid),query(o<<1|1,Mid+1,r));
179     pushup(o);
180 }
181 void rever(int o,int l,int r){
182     if(Node[o].l == l && Node[o].r == r){
183         change(Node[o].maxv,Node[o].minv);
184         Node[o].flag ^= 1;
185         return;
186     }
187     int Mid = (Node[o].l + Node[o].r) >> 1;
188     pushdown(o);
189     if(r <= Mid)
190         rever(o<<1,l,r);
191     else if(l > Mid)
192         rever(o<<1|1,l,r);
193     else{
194         rever(o<<1,l,Mid);
195         rever(o<<1|1,Mid+1,r);
196     }
197     pushup(o);
198 }
199 int find_max(int x,int y){
200     int f1 = top[x],f2 = top[y];
201     int ret = -100000;
202     
203     while(f1 != f2){
204         if(dep[f1] < dep[f2]){
205             swap(f1,f2);
206             swap(x,y);
207         }
208         ret = max(ret,query(1,Segnum[f1],Segnum[x]));
209         x = fa[f1];f1 = top[x];
210     }
211     
212     if(x == y)return ret;
213     if(dep[x] < dep[y]){
214         ret = max(ret,query(1,Segnum[son[x]],Segnum[y]));
215     }
216     else{
217         ret = max(ret,query(1,Segnum[son[y]],Segnum[x]));
218     }
219     
220     return ret;
221 }
222 
223 void get_rever(int x,int y){
224     int f1 = top[x],f2 = top[y];
225     
226     while(f1 != f2){
227         if(dep[f1] < dep[f2]){
228             swap(f1,f2);
229             swap(x,y);
230         }
231         rever(1,Segnum[f1],Segnum[x]);
232         x = fa[f1];f1 = top[x];
233     }
234     if(x == y)return;//如果是针对边的操作, 这个东西不能少。。 
235     if(dep[x] < dep[y]){
236         rever(1,Segnum[son[x]],Segnum[y]);//如果是边权,注意这里的写法。要下放。 
237     }
238     else{
239         rever(1,Segnum[son[y]],Segnum[x]);
240     }
241     return;
242 }
243 
244 void change(int &a,int &b){
245     int tp1 = a,tp2 = b;
246     a = -tp2;b = -tp1;
247     return;
248 }
树链剖分

 TLE的但是保证 不WA的LCT

  1 #include <cstdlib>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 #include <iostream>
  6 
  7 using namespace std;
  8 const int N = 20000 + 5;
  9 
 10 int n;
 11 int top, st[N << 1];
 12 int fa[N], c[N][2], val[N], mx[N];
 13 bool rev[N];
 14 
 15 void pushup(int x) {
 16   int l = c[x][0], r = c[x][1];
 17   mx[x] = x;
 18   if(l && val[mx[l]] > val[mx[x]]) mx[x] = mx[l];
 19   if(r && val[mx[r]] > val[mx[x]]) mx[x] = mx[r];
 20 }
 21 
 22 void pushdown(int x) {
 23   int l = c[x][0], r = c[x][1];
 24   if(rev[x]) {
 25     rev[x] ^= 1; rev[l] ^= 1; rev[r] ^= 1;
 26     swap(c[x][0], c[x][1]);
 27   }
 28 }
 29 
 30 bool isroot(int x) {
 31   return c[fa[x]][0] != x && c[fa[x]][1] != x;
 32 }
 33 
 34 void rotate(int x) {
 35   int y = fa[x], z = fa[y], l, r;
 36   if(c[y][0] == x) l = 0, r = 1;
 37   else l = 1, r = 0;
 38   if(!isroot(y)) {
 39     if(c[z][0] == y) c[z][0] = x;
 40     else c[z][1] = x;
 41   }
 42   fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
 43   c[y][l] = c[x][r]; c[x][r] = y;
 44   pushup(y); pushup(x);
 45 }
 46 
 47 void splay(int x) {
 48   top = 0; st[++ top] = x;
 49   for(int i = x; !isroot(i); i = fa[i])
 50     st[++ top] = fa[i];
 51   while(top) pushdown(st[top --]);
 52   while(!isroot(x)) {
 53     int y = fa[x], z = fa[y];
 54     if(!isroot(y)) {
 55       if((c[z][0] == y) ^ (c[y][0] == x)) rotate(x);
 56       else rotate(y);
 57     }
 58     rotate(x);
 59   }
 60   pushup(x);
 61 }
 62 
 63 void access(int x) {
 64   int t = 0;
 65   while(x) {
 66     splay(x); c[x][1] = t;
 67     t = x;
 68     pushup(x); x = fa[x];
 69   }
 70 }
 71 
 72 void mroot(int x) {
 73   access(x); splay(x); rev[x] ^= 1;
 74 }
 75 
 76 void link(int a, int b) {
 77   mroot(a); fa[a] = b;
 78 }
 79 
 80 void cut(int a, int b) {
 81   mroot(a); access(b); splay(b);
 82   c[b][0] = fa[c[b][0]] = 0;
 83 }
 84 
 85 int Q(int a, int b) {
 86   mroot(a); access(b); splay(b);
 87   return val[mx[b]];
 88 }
 89 
 90 void C(int a, int b) {
 91   access(a + n); splay(a + n);
 92   val[a + n] = b;
 93 }
 94 
 95 int main() {
 96   char ss[10];
 97   int a, b, t, cs;
 98   scanf("%d", &t);
 99   while(t --) {
100     memset(fa, 0, sizeof fa);
101     memset(rev, 0, sizeof rev);
102     memset(c, 0, sizeof c);
103     memset(mx, 0, sizeof mx);
104     memset(val, 0, sizeof val);
105     scanf("%d", &n);
106     for(int i = 1; i < n; ++ i) {
107       scanf("%d%d%d", &a, &b, &cs);
108       val[i + n] = cs;
109       mx[i + n] = i + n;
110       link(a, i + n); link(b, i + n);
111     }
112     while(1) {
113       scanf("%s", ss);
114       if(ss[0] == 'D') break;
115       if(ss[0] == 'C') {
116         scanf("%d%d", &a, &b);
117         C(a, b);
118       }
119       else {
120         scanf("%d%d", &a, &b);
121         printf("%d
", Q(a, b));
122       }
123     }
124   }
125   return 0;
126 }
lct

题目二: SPOJ Query On a Tree II

题目大意:

给一个树,两个操作,求a->b距离,求a->b路径上的第k个点。

算法讨论:

用LCA来维护,第k个点也用Lca来跳就可以啦。

  1 #include <cstdlib>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <iostream>
  6 
  7 using namespace std;
  8 
  9 const int N = 20000 + 5;
 10 
 11 int n, cnt;
 12 int head[N], fa[N], f[N][16];
 13 int dis[N], depth[N];
 14 
 15 struct Edge {
 16   int from, to, dis, next;
 17 }edges[N << 1];
 18 
 19 void insert(int from, int to, int w) {
 20   ++ cnt;
 21   edges[cnt].from = from; edges[cnt].to = to; edges[cnt].dis = w;
 22   edges[cnt].next = head[from]; head[from] = cnt;
 23 }
 24 
 25 void build(int u, int f) {
 26   fa[u] = f;
 27   for(int i = head[u]; i; i = edges[i].next) {
 28     int v = edges[i].to;
 29     if(v != f) {
 30       dis[v] = dis[u] + edges[i].dis;
 31       depth[v] = depth[u] + 1;
 32       build(v, u);
 33     }
 34   }
 35 }
 36 
 37 void prepare() {
 38   memset(f, -1, sizeof f);
 39   for(int i = 1; i <= n; ++ i) f[i][0] = fa[i];
 40   for(int j = 1; (1 << j) <= n; ++ j) {
 41     for(int i = 1; i <= n; ++ i) {
 42       if(f[i][j - 1] != -1) {
 43         f[i][j] = f[f[i][j - 1]][j - 1];
 44       }
 45     }
 46   }
 47 }
 48 
 49 int lca(int a, int b) {
 50   int i;
 51   if(depth[a] < depth[b]) swap(a, b);
 52   for(i = 0; (1 << i) <= depth[a]; ++ i);
 53   -- i;
 54   for(int j = i; j >= 0; -- j) {
 55     if(depth[a] - depth[b] >= (1 << j))
 56       a = f[a][j];
 57   }
 58   if(a == b) return a;
 59   for(int j = i; j >= 0; -- j) {
 60     if(f[a][j] != -1 && f[a][j] != f[b][j]) {
 61       a = f[a][j]; b = f[b][j];
 62     }
 63   }
 64   return f[a][0];
 65 }
 66 
 67 int splca(int a, int len) {
 68   int i;
 69   for(i = 0; (1 << i) <= depth[a]; ++ i);
 70   -- i;
 71   for(int j = i; j >= 0; -- j) {
 72     if(depth[a] - len >= (1 << j)) {
 73       a = f[a][j];
 74     }
 75   }
 76   return a;  
 77 }
 78 
 79 int Q(int a, int b) {
 80   return dis[a] + dis[b] - 2 * dis[lca(a, b)];
 81 }
 82 
 83 int K(int a, int b, int c) {
 84   int Lca = lca(a, b), res;
 85   if(depth[a] - depth[Lca] + 1 >= c) {
 86     res = splca(a, depth[Lca] + (depth[a] - depth[Lca]) - c + 1);
 87   }
 88   else {
 89     c -= (depth[a] - depth[Lca]);
 90     res = splca(b, depth[Lca] + c - 1);
 91   }
 92   return res;
 93 }
 94 
 95 void clear() {
 96   cnt = 0;
 97   memset(head, 0, sizeof head);
 98 }
 99 
100 int main() {
101   int t, u, v, w, a, b, c;
102   char ss[10];
103   bool flag = false;
104   scanf("%d", &t);
105   while(t --) {
106     if(flag) puts("");
107     flag = true;
108     clear();
109     scanf("%d", &n);
110     for(int i = 1; i < n; ++ i) {
111       scanf("%d%d%d", &u, &v, &w);
112       insert(u, v, w); insert(v, u, w);
113     }
114     depth[1] = 1;
115     dis[1] = 0;
116     build(1, 0);
117     prepare();
118     while(1) {
119       scanf("%s", ss);
120       if(ss[0] == 'D') {
121         if(ss[1] == 'O') break;
122         else {
123           scanf("%d%d", &a, &b);
124           printf("%d
", Q(a, b));
125         }
126       }
127       else {
128         scanf("%d%d%d", &a, &b, &c);
129         printf("%d
", K(a, b, c));
130       }
131     }
132   }
133   return 0;
134 }
Q2 LCA版

题目三 SPOJ Query On a Tree III

题目大意:

给出一棵树,每个点有权值,而且互不相同。求以某个点为根的子树中第k小的权值是哪个点。

算法讨论:

我的第一个做法是可持久化线段树 + 区间第K小值。我们知道一个点的子树在DFS序中一定是连续的,所以我们可以查询这个区间的第K小值。这就是可持久化线段树的应用。注意可持久化线段树是NlogN的空间,我居然忘记了,只开了原来的4倍。。。所以有三个点re了。

  1 #include <cstdlib>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <iostream>
  6 
  7 using namespace std;
  8 
  9 const int N = 150000 + 5;
 10 
 11 int n, m, cnt, tot, pos;
 12 int fa[N], size[N], num[N], mx[N], w[N];
 13 int root[N], rank[N], son[N], head[N], seg[N];
 14 
 15 struct Edge {
 16   int from, to, next;
 17 }edges[N << 1];
 18 
 19 struct SegTree {
 20   int l, r, size;
 21 }Node[N * 16];//注意可持久化线段树是NlogN的空间
 22 
 23 struct data {
 24   int v, pos, id;
 25   bool operator < (const data &k) const {
 26     return v < k.v;
 27   }
 28 }a[N];
 29 
 30 void insert(int from, int to) {
 31   ++ cnt;
 32   edges[cnt].from = from; edges[cnt].to = to;
 33   edges[cnt].next = head[from]; head[from] = cnt;
 34 }
 35 
 36 void dfs_1(int x, int f) {
 37   size[x] = 1;
 38   fa[x] = f;
 39   for(int i = head[x]; i; i = edges[i].next) {
 40     int v = edges[i].to;
 41     if(v != f) {
 42       dfs_1(v, x);
 43       size[x] += size[v];
 44       if(!son[x] || size[v] > size[son[x]])
 45         son[x] = v;
 46     }
 47   }
 48 }
 49 
 50 void dfs_2(int x, int ances) {
 51   mx[x] = num[x] = ++ pos;
 52   seg[pos] = x;
 53   if(!son[x]) return;
 54   dfs_2(son[x], ances);
 55   mx[x] = max(mx[x], mx[son[x]]);
 56   for(int i = head[x]; i; i = edges[i].next) {
 57     int v = edges[i].to;
 58     if(v != fa[x] && v != son[x]) {
 59       dfs_2(v, v);
 60       mx[x] = max(mx[x], mx[v]);
 61     }
 62   }
 63 }
 64 
 65 void build(int &o, int l, int r) {
 66   o = ++ tot;
 67   Node[o].l = Node[o].r = Node[o].size = 0;
 68   if(l >= r) return;
 69   int mid = (l + r) >> 1;
 70   build(Node[o].l, l, mid);
 71   build(Node[o].r, mid + 1, r);
 72 }
 73 
 74 void update(int pre, int &o, int l, int r, int kth) {
 75   o = ++ tot;
 76   Node[o] = Node[pre];
 77   Node[o].size ++;
 78   if(l >= r) return;
 79   int mid = (l + r) >> 1;
 80   if(kth <= mid)
 81     update(Node[pre].l, Node[o].l, l, mid, kth);
 82   else
 83     update(Node[pre].r, Node[o].r, mid + 1, r, kth);
 84 }
 85 
 86 int query(int r1, int r2, int l, int r, int kth) {
 87   if(l >= r) return l;
 88   int lc = Node[Node[r2].l].size - Node[Node[r1].l].size;
 89   int mid = (l + r) >> 1;
 90   if(lc >= kth) {
 91     int ans = query(Node[r1].l, Node[r2].l, l, mid, kth);
 92     return ans;
 93   }
 94   else {
 95     int ans = query(Node[r1].r, Node[r2].r, mid + 1, r, kth - lc);
 96     return ans;
 97   }
 98 }
 99 
100 int Q(int x, int k) {
101   int l = num[x], r = mx[x];
102   return  a[query(root[l - 1], root[r], 1, n, k)].id;
103 }
104 
105 int main() {
106   int u, v, x, k;
107   scanf("%d", &n);
108   for(int i = 1; i <= n; ++ i) scanf("%d", &w[i]);
109   for(int i = 1; i < n; ++ i) {
110     scanf("%d%d", &u, &v);
111     insert(u, v); insert(v, u);
112   }
113   dfs_1(1, 0); dfs_2(1, 1);
114   for(int i = 1; i <= n; ++ i) {
115     a[i].v = w[seg[i]];
116     a[i].pos = i;
117     a[i].id = seg[i];
118   }
119   sort(a + 1, a + n + 1);
120   for(int i = 1; i <= n; ++ i) {
121     rank[a[i].pos] = i;
122   }
123   build(root[0], 1, n);
124   for(int i = 1; i <= n; ++ i) {
125     update(root[i - 1], root[i], 1, n, rank[i]);
126   }
127   scanf("%d", &m);
128   for(int i = 1; i <= m; ++ i) {
129     scanf("%d%d", &x, &k);
130     printf("%d
", Q(x, k));
131   }
132   return 0;
133 }
可持久化线段树+树剖
  1 #include <cstdlib>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <iostream>
  6 
  7 using namespace std;
  8 
  9 const int N = 100000 + 5;
 10 
 11 int n, m, cnt, tot, pos;
 12 int fa[N], num[N], mx[N], w[N], st[N << 1];
 13 int root[N], rank[N], head[N], seg[N], fast[N];
 14 
 15 struct Edge {
 16   int from, to, next;
 17 }edges[N << 1];
 18 
 19 struct SegTree {
 20   int l, r, size;
 21 }Node[N * 20];
 22 
 23 struct data {
 24   int v, pos, id;
 25   bool operator < (const data &k) const {
 26     return v < k.v;
 27   }
 28 }a[N];
 29 
 30 //seg[i]  the ith pos is seg[i]
 31 //num[i] the i's pos in the segment tree.
 32 void dfs() {
 33   int top = 0;
 34   st[++ top] = 1;
 35   while(top) {
 36     int now = st[top], f = fast[top];
 37     top --;
 38     if(!num[now]) {
 39       num[now] = ++ pos;
 40       mx[now] = num[now];
 41       st[++ top] = now;
 42       fa[now] = f;
 43       for(int i = head[now]; i; i = edges[i].next) {
 44         if(edges[i].to != f) {
 45           st[++ top] = edges[i].to;
 46           fast[top] = now;
 47         }
 48       }
 49     }
 50   }
 51   for(int i = 1; i <= n; ++ i)
 52     seg[num[i]] = i;
 53   for(int i = n; i >= 1; -- i) {
 54     mx[fa[seg[i]]] = max(mx[seg[i]], mx[fa[seg[i]]]);
 55   }
 56 }
 57 
 58 void insert(int from, int to) {
 59   ++ cnt;
 60   edges[cnt].from = from; edges[cnt].to = to;
 61   edges[cnt].next = head[from]; head[from] = cnt;
 62 }
 63 
 64 void build(int &o, int l, int r) {
 65   o = ++ tot;
 66   Node[o].l = Node[o].r = Node[o].size = 0;
 67   if(l >= r) return;
 68   int mid = (l + r) >> 1;
 69   build(Node[o].l, l, mid);
 70   build(Node[o].r, mid + 1, r);
 71 }
 72 
 73 void update(int pre, int &o, int l, int r, int kth) {
 74   o = ++ tot;
 75   Node[o] = Node[pre];
 76   Node[o].size ++;
 77   if(l >= r) return;
 78   int mid = (l + r) >> 1;
 79   if(kth <= mid)
 80     update(Node[pre].l, Node[o].l, l, mid, kth);
 81   else
 82     update(Node[pre].r, Node[o].r, mid + 1, r, kth);
 83 }
 84 
 85 int query(int r1, int r2, int l, int r, int kth) {
 86   if(l >= r) return l;
 87   int lc = Node[Node[r2].l].size - Node[Node[r1].l].size;
 88   int mid = (l + r) >> 1;
 89   if(lc >= kth) {
 90     int ans = query(Node[r1].l, Node[r2].l, l, mid, kth);
 91     return ans;
 92   }
 93   else {
 94     int ans = query(Node[r1].r, Node[r2].r, mid + 1, r, kth - lc);
 95     return ans;
 96   }
 97 }
 98 
 99 int Q(int x, int k) {
100   int l = num[x], r = mx[x];
101   return  a[query(root[l - 1], root[r], 1, n, k)].id;
102 }
103 
104 int main() {
105   int u, v, x, k;
106   scanf("%d", &n);
107   for(int i = 1; i <= n; ++ i) scanf("%d", &w[i]);
108   for(int i = 1; i < n; ++ i) {
109     scanf("%d%d", &u, &v);
110     insert(u, v); insert(v, u);
111   }
112   dfs();
113   for(int i = 1; i <= n; ++ i) {
114     a[i].v = w[seg[i]];
115     a[i].pos = i;
116     a[i].id = seg[i];
117   }
118   sort(a + 1, a + n + 1);
119   for(int i = 1; i <= n; ++ i) {
120     rank[a[i].pos] = i;
121   }
122   build(root[0], 1, n);
123   for(int i = 1; i <= n; ++ i) {
124     update(root[i - 1], root[i], 1, n, rank[i]);
125   }
126   scanf("%d", &m);
127   for(int i = 1; i <= m; ++ i) {
128     scanf("%d%d", &x, &k);
129     printf("%d
", Q(x, k));
130   }
131   return 0;
132 }
人工栈+可持久化线段树
原文地址:https://www.cnblogs.com/sxprovence/p/5176350.html