BZOJ 2588 Count on a tree(树上的主席树)

来源:互联网 发布:webservice java 实例 编辑:程序博客网 时间:2024/06/06 03:16

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit:128 MB
Submit: 7489  Solved: 1824
[Submit][Status][Discuss]

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


强制在线的话就只能主席树了。

学的主席树只能处理序列, 怎么办呢?

其实dfs序也是个序列2333, 于是我们就可以对dfs序建主席树了

只不过root[i] 不是指向 root[i-1], 而是指向了dfn[fa[re[i]]], i 是当前点的dfs序,re[i]是当前点, 前缀和也不是序列前缀和了, 是树上前缀和

#include <cstdio>#include <algorithm>#define lson l, m, lch[now]#define rson m+1, r, rch[now]#define N 100005using namespace std;struct node{    int a, b, c, n;}d[N * 2];int lch[N * 20], rch[N * 20], rt[N * 20], sum[N * 20], dfn[N], h[N], re[N];int siz[N], top[N], son[N], fa[N], dep[N], w[N], tot, cnt, z, p, sz;int pai[N], v[N];void cr(int a, int b){    d[++z].a = a; d[z].b = b; d[z].n = h[a]; h[a] = z;}void dfs1(int a){    int i, b;    siz[a] = 1;    dfn[a] = ++cnt;    re[cnt] = a;    for(i = h[a]; i; i = d[i].n){        b = d[i].b;        if(b != fa[a]){            dep[b] = dep[a] + 1;            fa[b] = a;            dfs1(b);            if(siz[b] >= siz[son[a]]) son[a] = b;            siz[a] += siz[b];        }    }}void dfs2(int a, int tp){    int i, b;    top[a] = tp;    if(son[a]) dfs2(son[a], tp);    for(i = h[a]; i; i = d[i].n){        b = d[i].b;        if(b != fa[a] && son[a] != b) dfs2(b, b);    }}void update(int l, int r, int &now, int las, int pos){    now = ++p;    sum[now] = sum[las] + 1;    if(l == r) return;    lch[now] = lch[las];    rch[now] = rch[las];    int m = l+r>>1;    if(pos <= m) update(lson, lch[las], pos);    else update(rson, rch[las], pos);}int getlca(int a, int b){    int f1 = top[a], f2 = top[b];    while(f1 != f2){        if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);        a = fa[f1], f1 = top[a];    }    return dep[a] < dep[b] ? a : b;}int query(int l, int r, int k){    int a = l, b = r, c = getlca(a, b), d = fa[c], mid, cntt;    a = rt[dfn[a]], b = rt[dfn[b]], c = rt[dfn[c]], d = rt[dfn[d]];    l = 1, r = sz;    while(l < r){        mid = l+r>>1;        cntt = sum[lch[a]] + sum[lch[b]] - sum[lch[c]] - sum[lch[d]];        if(cntt >= k) r = mid, a = lch[a], b = lch[b], c = lch[c], d = lch[d];        else l = mid+1, a = rch[a], b = rch[b], c = rch[c], d = rch[d], k -= cntt;    }    return v[l];}int main(){    int i, j, n, m, lastans = 0, k, t, a, b, c;    scanf("%d%d", &n, &m);    for(i = 1; i <= n; i++) scanf("%d", &w[i]);    for(i = 1; i < n; i++){        scanf("%d%d", &a, &b);        cr(a, b); cr(b, a);    }    dfs1(1);     dfs2(1, 1);    for(i = 1; i <= n; i++) v[i] = pai[i] = w[i];    sort(v + 1, v + i);    sz = unique(v + 1, v + 1 + n) - (v + 1);    for(i = 1; i <= n; i++) pai[i] = lower_bound(v + 1, v + 1 + sz, w[i]) - v;    for(i = 1; i <= n; i++){        t = re[i];        update(1, sz, rt[i], rt[dfn[fa[t]]], pai[t]);    }    while(m--){        scanf("%d%d%d", &a, &b, &k);        a ^= lastans;        lastans = query(a, b, k);        if(m >= 1) printf("%d\n", lastans);        else printf("%d", lastans);    }    return 0;}


阅读全文
0 0
原创粉丝点击