SPOJ Problem Set (classical)SPOJ 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 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 nextm 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把树搞成括号序列,记录每个节点的开始和结束时间戳,然后就变成了区间第k大值,用划分树模板即可。
#include <stdio.h> #include <string.h> #include <algorithm> #include <map> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define BUG puts("here!!!") #define LL long long using namespace std; const int N=100005; int n,m; int val[40][N],sorted[N],toleft[40][N]; bool cmp(int a,int b) { return a<b; } struct node { int l,r; int getmid() { return (l+r)>>1; } } tree[N * 4]; void build(int rt,int l,int r,int d) { tree[rt].l=l; tree[rt].r=r; if(l==r) return; int mid=(l+r) >> 1; int same=mid-l+1; for(int i=l; i<=r; ++i) if (val[d][i]<sorted[mid])same--; int lpos=l; int rpos=mid+1; for(int i=l; i<=r; ++i) { if(i==l)toleft[d][i]=0; else toleft[d][i]=toleft[d][i - 1]; if(val[d][i]<sorted[mid]) { toleft[d][i]++; val[d+1][lpos++]=val[d][i]; } else if(val[d][i]>sorted[mid])val[d+1][rpos++]=val[d][i]; else if(same) { same--; toleft[d][i]++; val[d+1][lpos++]=val[d][i]; } else val[d+1][rpos++]=val[d][i]; } build(L(rt),l,mid,d+1); build(R(rt),mid+1,r,d+1); } int query(int rt, int l, int r, int d, int k) { if(l==r)return val[d][l]; int s,ss; if(l==tree[rt].l) { s=toleft[d][r]; ss=0; } else { s=toleft[d][r]-toleft[d][l-1]; ss=toleft[d][l-1]; } if(k<=s) { int left=tree[rt].l+ss; int right=left+s-1; return query(L(rt),left,right,d+1,k); } else { int b=l-tree[rt].l-ss; int left=tree[rt].getmid()+b+1; int right=left+r-l-s; return query(R(rt),left,right,d+1,k-s); } } int lab[N],one[N],two[N],eid,num; int head[N],ed[N<<1],nxt[N<<1]; map<int,int>ha; void addedge(int s,int e) { ed[eid]=e; nxt[eid]=head[s]; head[s]=eid++; } void dfs(int s,int f) { one[s]=num; sorted[num]=lab[s]; val[0][num++]=lab[s]; for(int i=head[s]; ~i; i=nxt[i]) if(ed[i]!=f)dfs(ed[i],s); two[s]=num-1; } int main() { // freopen("/home/axorb/in","r",stdin); ha.clear(); scanf("%d",&n); eid=0; memset(head,-1,sizeof(head)); for(int i=1; i<=n; i++) { scanf("%d",&lab[i]); ha[lab[i]]=i; } for(int i=1; i<n; i++) { int a,b; scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a); } num=0; dfs(1,-1); sort(sorted,sorted+n,cmp); build(1,0,n-1,0); int q; scanf("%d",&q); while(q--) { int a,b; scanf("%d%d",&a,&b); printf("%d\n",ha[query(1,one[a],two[a],0,b)]); } }