SPOJ 线段树(区间kth number) 1487. Query on a tree III

1487. Query on a tree III

Problem code: PT07J


You are given a node-labeled rooted tree with n nodes.

Define the query (xk): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels.

Input

The first line contains one integer n (1 <= n <= 105). The next line contains n integers li (0 <= li <= 109) which denotes the label of the i-th node.

Each line of the following n - 1 lines contains two integers uv. They denote there is an edge between nodeu and node v. Node 1 is the root of the tree.

The next line contains one integer m (1 <= m <= 104) which denotes the number of the queries. Each line of the next m contains two integers xk. (k <= the total node number in the subtree of x)

Output

For each query (xk), output the index of the node whose label is the k-th largest in the subtree of the node x.

Example

Input:
5
1 3 5 2 7
1 2
2 3
1 4
3 5
4
2 3
4 1
3 2
3 2

Output:
5
4
5
5

题意:有一棵树,每个点有一个权值,每个点的权值各不相同,求出字数x中第k大的权值是多少,保证k不超过字数的大小。


思路:根据dfs序建立线段树,剩下就是求区间第k大问题,首先这道题目不要用任何的stl,不然tle的,因为stl释放起来很慢、很慢,省赛已经吃过一次亏了。 然后第k大怎么求呢?zkw 统计的力量里面有讲,我们线段树上保存该段的有序数列,然后我们离散化后,二分一个数,求这个数在[L,R]里面排名是多少。对应线段树里面每一段满足L<=l&&r<=R的,求出该段有多少数比当前二分的值要小,然后把各段累加起来,就能知道该树排第几,然后这样可能会有多个数排名都是k的,我们只需要保留最大的就行了,因为只有最大才是在[L,R]里面的数,如果刚好比这个数大,排名就是k+1了。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <string.h>
using namespace std;
const int maxn=100000+5;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1

int n,dfn;
int L[maxn],R[maxn],value[maxn],node[maxn];
int * v[280000];
int len[280000];
struct Node
{
    int v;
    Node *next;
}*first[maxn],edges[maxn*2];
int ptr;

void add(int u,int v)
{
    edges[++ptr].v=v;
    edges[ptr].next=first[u];
    first[u]=&edges[ptr];
}

int to[maxn];
bool cmp(int x,int y) { return value[x]<value[y]; }

void build(int l,int r,int rt)
{
     if(l==r) {
         v[rt]=new int[1];
         v[rt][0]=value[node[l]];
         len[rt]=1;
         return;
     }
     int m=(l+r)>>1;
     build(lson); build(rson);
     int i=0,j=0,k=len[ls]+len[rs];
     len[rt]=k;
     v[rt]=new int[k];
     k=0;
     while(i<len[ls]||j<len[rs]) {
          if(i>=len[ls]) { v[rt][k++]=v[rs][j]; ++j; }
          else if(j>=len[rs]) { v[rt][k++]=v[ls][i]; ++i; }
          else if(v[ls][i]<=v[rs][j]) { v[rt][k++]=v[ls][i]; ++i; }
          else { v[rt][k++]=v[rs][j]; ++j; }
     }
}

int stk[maxn*2];
bool vis[maxn];
void dfs(int u,int fa)
{
    memset(vis,0,sizeof(vis));
    int top=0;
    stk[++top]=u;
    while(top>0) {
        u=stk[top];
        if(vis[u]) {
            R[u]=dfn;
            --top;
            continue;
        }
        vis[u]=true; L[u]=++dfn; node[dfn]=u;
        for(Node*p=first[u];p!=NULL;p=p->next) {
            int v=p->v;
            if(vis[v]) continue;
            stk[++top]=v;
        }
    }
//     L[u]=++dfn; node[dfn]=u;
//     for(Node *p=first[u];p!=NULL;p=p->next) {
//          int v=p->v;
//          if(v==fa) continue;
//          dfs(v,u);
//     }
//     R[u]=dfn;
    // printf("%d : %d %d\n",u,L[u],R[u]);
}

void read_int(int&a)
{
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    a=ch-'0';
    ch=getchar();
    while('0'<=ch&&ch<='9') {
        a=a*10+ch-'0';
        ch=getchar();
    }
}
void input()
{
    memset(first,0,sizeof(first));
    ptr=0;
     for(int i=1;i<=n;++i) {
        read_int(value[i]);
        //scanf("%d",&value[i]);
        to[i]=i;
     }
     for(int i=1;i<n;++i) {
          int u,v;
         read_int(u); read_int(v);
         //scanf("%d%d",&u,&v);
         add(u,v); add(v,u);
     }
     dfn=0;
     dfs(1,-1);
}

int k;

int binsearch(int left,int right,int * a,int x)
{
    int mid;
    while(left<=right) {
        mid=(left+right)>>1;
        if(a[mid]<x) left=mid+1;
        else right=mid-1;
    }
    return left;
}

int kth(int L,int R,int x,int l,int r,int rt)
{
     if(L<=l&&r<=R)
          // return lower_bound(v[rt],v[rt]+len[rt],x)-v[rt];
          return binsearch(0,len[rt]-1,v[rt],x);
     int rank=0;
     int m=(l+r)>>1;
     if(L<=m) rank+=kth(L,R,x,lson);
     if(rank>=k) return rank;
     if(m<R) rank+=kth(L,R,x,rson);
     return rank;
}

int ID(int x)
{
    int left=1,right=n;
    while(left<=right) {
        int mid=(left+right)>>1;
        if(value[to[mid]]<x) left=mid+1;
        else if(value[to[mid]]==x) return to[mid];
        else right=mid-1;
    }
    while(1);
    return -1;
}

void solve()
{
    build(1,n,1);
     int q; scanf("%d",&q);
     sort(to+1,to+1+n,cmp);
     int x,l,r,m,rank;
     while(q--) {
          read_int(x); read_int(k);
          //scanf("%d%d",&x,&k);
          l=1,r=n;
          int ans=-1;
          while(l<=r) {
                m=(l+r)>>1;
                rank=kth(L[x],R[x],value[to[m]],1,n,1);
                if(rank<=k-1) {
                    if(rank==k-1&&ans<value[to[m]]) ans=value[to[m]];
                    l=m+1;
                }
                else r=m-1;
          }
          printf("%d\n",ID(ans));
     }
}

void release(int l,int r,int rt)
{
    delete [] v[rt];
    if(l==r) return;
    int m=(l+r)>>1;
    release(lson); release(rson);
}

void GetInput()
{
    freopen("in.txt","w",stdout);
    n=100000; printf("%d\n",n);
    for(int i=0;i<n;++i) printf("%d ",i);
    puts("");
    for(int i=1;i<n;++i) printf("%d %d\n",i,i+1);
    printf("10000\n");
    for(int i=0;i<10000;++i) {
        int x=rand()%n+1; k=rand()%(n-x+1)+1;
        printf("%d %d\n",x,k);
    }
}

int main()
{
   // GetInput(); return 0;
    freopen("in.txt","r",stdin);
     while(scanf("%d",&n)==1) {
          input();
          solve();
         //release(1,n,1);
     }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值