BZOJ 1803: Spoj1487 Query on a tree III【DFS序+主席树】

本文介绍了一种使用DFS序和主席树来优化树状结构上的查询问题的方法,并提供了一个具体的编程实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1803: Spoj1487 Query on a tree III

【题目描述】
传送门

【题解】

DFS序将树变成序列,然后用主席树维护就可以了。

代码如下

#include<cstdio>
#include<cctype>
#include<algorithm>
#define MAXN 100005
using namespace std;
int n,m,cnt,a[MAXN],W[MAXN],ID[MAXN],Siz[MAXN],hsh[MAXN],Place[MAXN];
int tot,T[MAXN],Sum[MAXN<<5],L[MAXN<<5],R[MAXN<<5];
struct Edge{
    int tot,lnk[MAXN],son[MAXN<<2],nxt[MAXN<<2];
    void Add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
int read(){
    int ret=0;bool f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
    return f?ret:-ret;
}
bool cmp(int x,int y){return a[x]<a[y];}
void DFS(int x,int f){
    W[++cnt]=a[x];ID[x]=cnt;Siz[x]=1;
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(E.son[j]!=f) DFS(E.son[j],x),Siz[x]+=Siz[E.son[j]];
}
int Updata(int lst,int l,int r,int p){
    int rt=++tot;
    Sum[rt]=Sum[lst]+1;L[rt]=L[lst],R[rt]=R[lst];
    if(l<r){
        int mid=(l+r)>>1;
        if(p<=mid) L[rt]=Updata(L[lst],l,mid,p);
        else R[rt]=Updata(R[lst],mid+1,r,p);
    }
    return rt;
}
int Query(int u,int v,int l,int r,int p){
    if(l>=r) return l;
    int Now=Sum[L[v]]-Sum[L[u]],mid=(r+l)>>1;
    if(p<=Now) return Query(L[u],L[v],l,mid,p);
    else return Query(R[u],R[v],mid+1,r,p-Now);
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),hsh[i]=a[i],Place[i]=i;
    sort(hsh+1,hsh+1+n);sort(Place+1,Place+1+n,cmp);
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        E.Add(x,y),E.Add(y,x);
    }
    DFS(1,0);
    for(int i=1;i<=n;i++) T[i]=Updata(T[i-1],1,n,lower_bound(hsh+1,hsh+1+n,W[i])-hsh);
    m=read();
    for(int i=1;i<=m;i++){
        int x=read(),k=read();
        printf("%d\n",Place[Query(T[ID[x]-1],T[ID[x]+Siz[x]-1],1,n,k)]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/XSamsara/p/9190118.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值