spoj PT07J Query on a tree III (主席树+dfs序)

题意:

一棵树,每次查询某个子树的第k大

思路:

     询问子树的问题,因为子树的dfs序是连续的一个区间,所以我们将这棵树dfs地建立主席树,查询子树就是查询子树对应的区间,这样就把树变成数列了

错误及反思:

     其实很简单,但是spoj卡常啊,在优化了常数,vector变成链式前向星,用了快读,换头文件以后终于ac了

代码:

#include<map>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define lson l,m
#define rson m+1,r
const int N = 101000;
int sum[N*20],ls[N*20],rs[N*20],val[N],root[N],fa[N],to[N],rnk[N],id[N],first[N];
int n,q,tot=1,cnt=0,tid=0;
vector<int> v;
map<int,int> mp;

struct EDGE{
    int to,next;
}e[N*2];

inline int read() {
    char ch = getchar(); int x = 0, f = 1;
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    } while('0' <= ch && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    } return x * f;
}

void addedge(int x,int y){
    e[tid].to=y;
    e[tid].next=first[x];
    first[x]=tid++;
    e[tid].to=x;
    e[tid].next=first[y];
    first[y]=tid++;
}


int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}

int build(int l,int r){
    int rt=++cnt;
    ls[rt]=rt; rs[rt]=rt; sum[rt]=0;
    if(l==r) return rt;
    int m=l+r>>1;
    ls[rt]=build(lson);
    rs[rt]=build(rson);
    return rt;
}

int update(int pre,int pos,int l,int r){
    int rt=++cnt;
    ls[rt]=ls[pre]; rs[rt]=rs[pre]; sum[rt]=sum[pre]+1;
    if(l==r) return rt;
    int m=l+r>>1;
    if(m>=pos) ls[rt]=update(ls[pre],pos,lson);
    else rs[rt]=update(rs[pre],pos,rson);
    return rt;
}

void dfs(int now,int Fa){
    root[tot]=update(root[tot-1],getid(val[now]),1,v.size());
    id[now]=tot;
    fa[now]=Fa; tot++;
    for(int i=first[now];i!=-1;i=e[i].next)
        if(e[i].to!=Fa)
            dfs(e[i].to,now);

    to[now]=tot-1;
}

int query(int r1,int r2,int k,int l,int r){
    if(l==r) return rnk[l-1];
    int m=l+r>>1,num=sum[ls[r2]]-sum[ls[r1]];
    if(num>=k) return query(ls[r1],ls[r2],k,lson);
    return query(rs[r1],rs[r2],k-num,rson);
}

int main(){
    memset(first,-1,sizeof(first));
    n=read();
    for(int i=1;i<=n;i++){ val[i]=read(); mp[val[i]]=i; v.push_back(val[i]);}
    sort(v.begin(),v.end());
    for(int i=0;i<v.size();i++){
        rnk[i]=mp[v[i]];
    }
    for(int i=1,u,v;i<n;i++){
        u=read(); v=read();
        addedge(u,v);
    }
    root[0]=build(1,v.size());
    dfs(1,0);

    scanf("%d",&q);
    while(q--){
        int x,k;scanf("%d%d",&x,&k);
        printf("%d\n",query(root[id[x]-1],root[to[x]],k,1,v.size()));
    }
}

猜你喜欢

转载自blog.csdn.net/roll_keyboard/article/details/80670865