P1487-Query on a tree III(裸dfs序+主席树)

题目
在这里插入图片描述
1<=n<=1e5,1<=m<=1e4;
输入样例#1:
5
1 3 5 2 7
1 2
2 3
1 4
3 5
4
2 3
4 1
3 2
3 2

输出样例#1:
5
4
5
5

题解:这个题输出子树第K小这个值对应原数列的哪一个 也就是可通过主席树+dfs序求出ai,但是要输出i。
因为要离散化。1-n数组 预处理一下id[dex]=i,dex是指离散化后的“权值”。
平常输出ai是则输出refl[query()],这里输出id[query()]。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct Edge{int to,nex;}edge[N<<1];int head[N],tot;
void add(int from,int to){
    edge[++tot]=(Edge){to,head[from]},head[from]=tot;
}
struct tree{int l,r,sum;}t[N*20];
int root[N],sz;
void update(int pos,int& x,int y,int l,int r){
    t[x=++sz]=t[y],++t[x].sum;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(pos<=mid) update(pos,t[x].l,t[y].l,l,mid);
    else update(pos,t[x].r,t[y].r,mid+1,r);
}
int query(int K,int x,int y,int l,int r){
    if(l==r) return l;
    int mid=(l+r)>>1,left=t[t[y].l].sum-t[t[x].l].sum;
    if(K<=left) return query(K,t[x].l,t[y].l,l,mid);
    return query(K-left,t[x].r,t[y].r,mid+1,r);
}
int in[N],out[N],fp[N],n;
void dfs(int x){
    in[x]=n++,fp[n-1]=x;
    for(int i=head[x];i;i=edge[i].nex) dfs(edge[i].to);
    out[x]=n-1;
}
int a[N],val[N],refl[N],id[N];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]),refl[i]=a[i];
    sort(refl+1,refl+n+1);
    int tot=unique(refl+1,refl+n+1)-(refl+1);
    for(int i=1,x,y;i<n;++i) scanf("%d%d",&x,&y),add(x,y);
    n=1,dfs(1),--n;
    for(int i=1;i<=n;++i) id[lower_bound(refl+1,refl+tot+1,a[i])-refl]=i;
    for(int i=1;i<=n;++i){
        int dex=lower_bound(refl+1,refl+tot+1,a[fp[i]])-refl;
        update(dex,root[i],root[i-1],1,tot);
    }
    int q;scanf("%d",&q);
    while(q--){
        int x,K;scanf("%d%d",&x,&K);
        printf("%d\n",id[query(K,root[in[x]-1],root[out[x]],1,tot)]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值