[BZOJ2588][Spoj 10628]COT

Spoj 10628. 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

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;
}

你可能感兴趣的:(可持久化线段树)