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 (x, k): 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 u, v. 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 x, k. (k <= the total node number in the subtree of x)
Output
For each query (x, k), 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); }}
- SPOJ 线段树(区间kth number) 1487. Query on a tree III
- hdu 2665 Kth number (函数式线段树)+ SPOJ Count on a tree
- SPOJ 1487 Query on a tree III 主席树,可持续化线段树
- Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)
- SPOJ - QTREE 375 Query on a tree 树链剖分+线段树
- SPOJ 375 Query on a tree (树链剖分+线段树)
- SPOJ Query on a tree (树链剖分 + 线段树)
- SPOJ QTREE Query on a tree [树链剖分+线段树]
- spoj qtree Query on a tree 【线段树+树链剖分】
- SPOJ QTREE Query on a tree(树链剖分+线段树)
- 【动态树】 SPOJ Query on a tree
- SPOJ PTO7J Query on a tree III(dfs序+主席树)
- SPOJ PT07J Query on a tree III(dfs序,主席树)
- SPOJ Query on a tree
- SPOJ Query on a tree
- SPOJ Query on a tree
- Query on a tree SPOJ
- Query on a tree SPOJ
- com.mysql.jdbc.CommunicationsException: Communications link failure之解决办法
- jetty处理请求路径与tomcat的不同,图片出不来
- 建立虚拟内存文件
- Freeradius+Mysql实现用户认证
- Linux进程间通信——有名管道
- SPOJ 线段树(区间kth number) 1487. Query on a tree III
- 类加载器总结
- spring各种邮件发送
- Delphi XE程序设计系列 2-开发DataSnap/REST服务器
- eclispe中maven工程配置 maven build报错java.lang.NullPointerException解决方法
- C++ 模板中的template typename 和template class的区别
- [LeetCode]—Subsets II 求数组子集(有重复值)
- 托福作文笔记
- 关于ul下<li></li>内插入<span>内容</span>标签自动换行不在同一行问题