[ SPOJ 1487 ] Query on a tree III
阿新 • • 發佈:2018-11-04
\(\\\)
Description
給定 \(n\) 個點,以 \(1\) 號節點為根的樹,點有點權。
\(m\) 次詢問 以 \(x\) 為根的子樹內,點權第 \(k\) 小的 節點編號 是多少。
有多組測試資料,每組資料以 \(DONE\) 結尾。
- \(n,m\le 10^5\)
\(\\\)
Solution
注意到一棵樹的子樹 \(DFS\) 序是連續的。
一遍 \(DFS\) 確定 \(DFS\) 序以及各個點的子樹大小。
在 \(DFS\) 序上建主席樹就可以了。
查子樹查的其實就是 \((dfn[x]-1,dfn[x]+size[x]-1]\)
注意查的是點的編號,但是注意到點權兩兩不同,就可以離散化後記錄每一個點權對應的節點編號了。
主席樹注意空間 開成17倍成功RE
\(\\\)
Code
#include<cmath> #include<cstdio> #include<cctype> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100010 #define gc getchar #define Rg register #define mid ((l+r)>>1) using namespace std; inline int rd(){ int x=0; bool f=0; char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();} return f?-x:x; } int n,m,tot,hd[N],val[N],tmp[N],len; struct edge{int to,nxt;}e[N<<1]; inline void add(int u,int v){ e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot; } int cnt,dfn[N],sz[N],vpos[N],pos[N]; void dfs(int u,int fa){ sz[u]=1; dfn[u]=++cnt; vpos[cnt]=val[u]; for(Rg int i=hd[u],v;i;i=e[i].nxt) if((v=e[i].to)!=fa){dfs(v,u);sz[u]+=sz[v];} } struct seg{ int rot[N],ptr; inline int newnode(){return ++ptr;} struct node{int ls,rs,sum;}c[N*20]; void build(int &rt,int l,int r){ rt=newnode(); if(l==r) return; build(c[rt].ls,l,mid); build(c[rt].rs,mid+1,r); } inline void pushup(int rt){ c[rt].sum=c[c[rt].ls].sum+c[c[rt].rs].sum; } void insert(int &rt,int lst,int l,int r,int x){ rt=newnode(); if(l==r){c[rt].sum=c[lst].sum+1;return;} if(x<=mid){ c[rt].rs=c[lst].rs; insert(c[rt].ls,c[lst].ls,l,mid,x); } else{ c[rt].ls=c[lst].ls; insert(c[rt].rs,c[lst].rs,mid+1,r,x); } pushup(rt); } inline int query(int rtl,int rtr,int l,int r,int k){ if(l==r) return l; int nowans=c[c[rtr].ls].sum-c[c[rtl].ls].sum; if(k<=nowans) return query(c[rtl].ls,c[rtr].ls,l,mid,k); else return query(c[rtl].rs,c[rtr].rs,mid+1,r,k-nowans); } }tree; int main(){ n=rd(); for(Rg int i=1;i<=n;++i) tmp[i]=val[i]=rd(); sort(tmp+1,tmp+1+n); for(Rg int i=1;i<=n;++i){ tmp[++len]=tmp[i]; while(tmp[i+1]==tmp[i]) ++i; } for(Rg int i=1;i<=n;++i){ val[i]=lower_bound(tmp+1,tmp+1+len,val[i])-tmp; pos[val[i]]=i; } for(Rg int i=1,u,v;i<n;++i){ u=rd(); v=rd(); add(u,v); add(v,u); } dfs(1,0); tree.build(tree.rot[0],1,len); for(Rg int i=1;i<=n;++i) tree.insert(tree.rot[i],tree.rot[i-1],1,len,vpos[i]); m=rd(); for(Rg int i=1,rt,k;i<=m;++i){ rt=rd(); k=rd(); printf("%d\n",pos[tree.query(tree.rot[dfn[rt]-1],tree.rot[dfn[rt]+sz[rt]-1],1,len,k)]); } return 0; }