1487. Query on a tree IIIProblem 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: 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);
}
}