SPOJ PT07J Query on a tree III(dfs序,主席树)

dfs序变为线性的序列,然后就是主席树区间第k大

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;

#pragma comment(linxer, "/STACK:102400000,102400000")
#define LL long long 
#define pii pair<int, int>
#define MP make_pair
#define ls i << 1
#define rs ls | 1
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define mod 1000000007
#define inf 0x3f3f3f3f
#define N 100010
#define M 200020

int ch[N*20][2], sum[N*20], nam[N], rt[N], tot;
int fst[N], vv[M], nxt[M], e;
int dc, st[N], ed[N], lab[N];
int san[N], cnt, val[N];
int haxi(int v){
    return lower_bound(san + 1, san + 1 + cnt, v) - san;
}
void init(){
    memset(fst, -1, sizeof fst); e = 0;
}
void add(int u, int v){
    vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
}
void dfs(int u, int p){
    st[u] = ++dc; lab[dc] = u;
    for(int i = fst[u]; ~i; i = nxt[i]){
        int v = vv[i];
        if(v == p) continue;
        dfs(v, u);
    }
    ed[u] = dc;
}
int update(int x, int v, int ll, int rr, int i){
    int k = ++tot;
    ch[k][0] = ch[i][0], ch[k][1] = ch[i][1];
    sum[k] = sum[i] + 1;
    if(ll == rr){
        nam[ll] = v;
        return k;
    }
    if(x <= md) ch[k][0] = update(x, v, ll, md, ch[i][0]);
    else ch[k][1] = update(x, v, md + 1, rr, ch[i][1]);
    return k;
}
int query(int l, int r, int ll, int rr, int k){
    if(ll == rr) return nam[ll];
    int tmp = sum[ch[r][0]] - sum[ch[l][0]];
    if(tmp >= k)
        return query(ch[l][0], ch[r][0], ll, md, k);
    else return query(ch[l][1], ch[r][1], md + 1, rr, k - tmp);
}

int main(){
    int n;
    while(scanf("%d", &n) != EOF){
        tot = cnt = 0;
        memset(ch, 0, sizeof ch);
        memset(sum, 0, sizeof sum);
        init();
        for(int i = 1; i <= n; ++i){
            scanf("%d", &val[i]);
            san[++cnt] = val[i];
        }
        sort(san + 1, san + 1 + cnt);
        cnt = unique(san + 1, san + 1 + cnt) - san - 1;
        for(int i = 1; i <= n; ++i)
            val[i] = haxi(val[i]);
        for(int i = 1; i < n; ++i){
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        dc = 0;
        dfs(1, -1);
        rt[0] = 0;
        for(int i = 1; i <= n; ++i){
            rt[i] = update(val[lab[i]], lab[i], 1, n, rt[i-1]);
        }
        int q;
        scanf("%d", &q);
        while(q--){
            int L, R, u, k;
            scanf("%d%d", &u, &k);
            L = st[u], R = ed[u];
            printf("%d\n", query(rt[L-1], rt[R], 1, n, k));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值