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

来源:互联网 发布:朗读软件下载 编辑:程序博客网 时间:2024/06/05 20:31

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:51 3 5 2 71 22 31 43 542 34 13 23 2Output:5455

题意:有一棵树,每个点有一个权值,每个点的权值各不相同,求出字数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|1int 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
原创粉丝点击