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
Solution
同BZOJ3524
Code
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int
n, m, sz, top = 1,
sum[2000005], lc[2000005], rc[2000005],
fa[MAXN][17], dep[MAXN], w[MAXN], last[MAXN], root[MAXN], hash[MAXN], q[MAXN << 1];
struct node{ int to, nxt; } edge[200005];
inline int read(){
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
inline void AddEdge(int u, int v){
edge[++top].to = v; edge[top].nxt = last[u]; last[u] = top;
edge[++top].to = u; edge[top].nxt = last[v]; last[v] = top;
}
void modify(int l, int r, int x, int &y, int pos){
y = ++sz;
sum[y] = sum[x] + 1; lc[y] = lc[x]; rc[y] = rc[x];
if (l == r) return;
int mid = l + r >> 1;
if (pos <= mid) modify(l, mid, lc[x], lc[y], pos); else modify(mid + 1, r, rc[x], rc[y], pos);
}
int get_lca(int x, int y){
if (dep[x] < dep[y]) swap(x, y);
int t = dep[x] - dep[y];
for(int i = 0; i <= 16; i++)
if((1 << i) & t) x = fa[x][i];
if (x == y) return y;
for (int i = 16; i >= 0; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int query(int l, int r, int son1, int son2, int anc1, int anc2, int k){
if (l == r) return l;
int res = sum[lc[son1]] + sum[lc[son2]] - sum[lc[anc1]] - sum[lc[anc2]];
int mid = l + r >> 1;
if (res >= k) return query(l, mid, lc[son1], lc[son2], lc[anc1], lc[anc2], k);
else return query(mid + 1, r, rc[son1], rc[son2], rc[anc1], rc[anc2], k - res);
}
int main(){
n = read(); m = read();
for (int i = 1; i <= n; i++) w[i] = read();
for (int i = 1; i <= n; i++) hash[i] = w[i];
sort(hash + 1, hash + 1 + n);
int tot = unique(hash + 1, hash + 1 + n) - hash - 1;
for (int i = 1; i < n; i++){
int u = read(), v = read(); AddEdge(u, v);
}
int l, r, now;
for (q[l = r = 1] = 1; l <= r; l++){
now = q[l];
for (int p = last[now]; p; p = edge[p].nxt) if (edge[p].to != fa[now][0]){
fa[q[++r] = edge[p].to][0] = now; dep[edge[p].to] = dep[now] + 1;
}
for (int i = 1; i <= 16 && (1 << i) <= dep[now]; i++) fa[now][i] = fa[fa[now][i - 1]][i - 1];
modify(1, tot, root[fa[now][0]], root[now], lower_bound(hash + 1, hash + 1 + tot, w[now]) - hash);
}
int last = 0;
for (int i = 1; i <= m; i++){
int u = read() ^ last, v = read(), k = read();
int anc = get_lca(u, v), ancanc = fa[anc][0];
printf("%d", last = hash[query(1, tot, root[u], root[v], root[anc], root[ancanc], k)]);
if (i != m) printf("\n");
}
return 0;
}