您的位置:首页 > 产品设计 > UI/UE

SPOJ PT07J - Query on a tree III(划分树)

2017-02-22 16:06 399 查看

PT07J - Query on a tree III

#treeYou 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 node u 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
【分析】给你一棵树以及每个节点的权值,求某个节点以及往下子孙中第K大的节点是哪个。
先DFS给每个节点编号,然后对于每个节点记录他的开始编号和结束编号,然后就是划分树模板了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson(x) ((x<<1))
#define rson(x) ((x<<1)+1)
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int M=1e6+10;
int le
,re
,lab
,sorted
;
int n,m,k,num=0;
map<int,int>mp;
struct Edge {
int to,next;
} edg[N*2];
int head
,tot;
void init() {
tot = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v) {
edg[tot].to = v;
edg[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u,int fa) {
le[u]=++num;
sorted[num]=lab[u];
for(int i=head[u]; i!=-1; i=edg[i].next) {
int v=edg[i].to;
if(v!=fa) {
dfs(v,u);
}
}
re[u]=num;
}
int tree[20]
;
int toleft[20]
;
void build(int l,int r,int dep) {
if(l==r)return;
int mid=(l+r)>>1;
int same=mid-l+1;
for(int i=l; i<=r; i++)
if(tree[dep][i]<sorted[mid])
same--;
int lpos=l;
int rpos=mid+1;
for(int i=l; i<=r; i++) {
if(tree[dep][i]<sorted[mid]) { //去左边
tree[dep+1][lpos++]=tree[dep][i];
} else if(tree[dep][i]==sorted[mid]&&same>0) { //去左边
tree[dep+1][lpos++]=tree[dep][i];
same--;
} else //去右边
tree[dep+1][rpos++]=tree[dep][i];
toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数
}
build(l,mid,dep+1);//递归建树
build(mid+1,r,dep+1);
}
void initBuild() {
for(int i=0; i<20; i++)tree[i][0]=toleft[i][0]=0;
for(int i=1; i<=n; i++) {
tree[0][i]=sorted[i];
}
sort(sorted+1,sorted+n+1);
build(1,n,0);
}

int query(int L,int R,int l,int r,int dep,int k) {
if(l==r)return tree[dep][l];
int mid=(L+R)>>1;
int cnt=toleft[dep][r]-toleft[dep][l-1];
if(cnt>=k) {
//L+查询区间前去左边的数的个数
int newl=L+toleft[dep][l-1]-toleft[dep][L-1];
//左端点+查询区间会分入左边的数的个数
int newr=newl+cnt-1;
return query(L,mid,newl,newr,dep+1,k);//注意
} else {
//r+区间后分入左边的数的个数
int newr=r+toleft[dep][R]-toleft[dep][r];
//右端点减去区间分入右边的数的个数
int newl=newr-(r-l-cnt);
return query(mid+1,R,newl,newr,dep+1,k-cnt);//注意
}
}
int main() {
int u,v,x;
init();
scanf("%d",&n);
for(int i=1; i<=n; i++){
scanf("%d",&lab[i]);
mp[lab[i]]=i;
}
for(int i=1; i<n; i++) {
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(1,0);
initBuild();
scanf("%d",&m);
while(m--){
scanf("%d%d",&x,&k);
u=le[x];v=re[x];
int ans=query(1,n,u,v,0,k);
printf("%d\n",mp[ans]);
}
return 0;
}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: