树上第k小,可持久化线段树+倍增lca
给定一颗树,树的每个结点都有权值,
有q个询问,每个询问是 u v k ,表示u到v路径上第k小的权值是多少。
每个结点所表示的线段树,是父亲结点的线段树添加该结点的权值之后形成的新的线段树
c[root] 表示根为root的子树添加了多少个结点。
那么c[lson[u]] + c[lson[v]] - c[lson[lca(u,v)]] - c[lson[fa[lca(u,v)]]] >=k ,那么说明左子树添加了k个以上的结点,说明第k小的值在左子树
否则就在右子树。
1 // 2 // main.cpp 3 // 函数式线段树 4 // 5 // Created by whoami on 15/9/21. 6 // Copyright (c) 2015年 whoami. All rights reserved. 7 // 8 9 #include <iostream> 10 #include <algorithm> 11 #include <stdio.h> 12 #include <string.h> 13 using namespace std; 14 const int N = 3000000 + 10; 15 const int M = 200000; 16 int t[N],lson[N],rson[N],c[N],total; 17 int a[M],b[M]; 18 int n,m,q; 19 int head[M],nxt[M],to[M],e; 20 int dfs_clock,iid[M]; 21 int fa[M][30],depth[M]; 22 void addEdge(int u, int v){ 23 to[e] = v; 24 nxt[e] = head[u]; 25 head[u] = e++; 26 } 27 28 //离散化,离散化后有多少个点,线段树的区间就是多大 29 void initHash(){ 30 sort(b+1,b+n+1); 31 m = unique(b+1,b+n+1) - b - 1; 32 } 33 int hs(int x){ 34 return lower_bound(b+1,b+m+1,x)-b; 35 } 36 37 int build(int l, int r){ 38 int root = total++; 39 c[root] = 0; 40 if(l!=r){ 41 int mid = (l+r)>>1; 42 lson[root] = build(l,mid); 43 rson[root] = build(mid+1,r); 44 } 45 return root; 46 } 47 int update(int root, int pos, int val){ 48 int newRoot = total++,tmp = newRoot; 49 c[newRoot] = c[root] + val; 50 int l =1, r = m; 51 while(l<r){ 52 int mid = (l+r)>>1; 53 if(pos<=mid){ 54 r = mid; 55 lson[newRoot] = total++; 56 rson[newRoot] = rson[root]; 57 newRoot = lson[newRoot]; 58 root = lson[root]; 59 } 60 else{ 61 l = mid + 1; 62 lson[newRoot] = lson[root]; 63 rson[newRoot] = total++; 64 newRoot = rson[newRoot]; 65 root = rson[root]; 66 } 67 c[newRoot] = c[root] + val; 68 } 69 return tmp; 70 } 71 void dfs(int u, int f, int dep){ 72 fa[u][0] = f; 73 depth[u] = dep; 74 75 for(int i=head[u]; i+1;i=nxt[i]){ 76 int v = to[i]; 77 if(v==f)continue; 78 t[++dfs_clock] = update(iid[u],hs(a[v]),1); 79 iid[v] = t[dfs_clock]; 80 dfs(v,u,dep+1); 81 } 82 } 83 84 int query(int urt, int vrt, int lcart, int frt, int k){ 85 int l = 1, r = m; 86 //当l==r,即区间的长度只有1时,那么该区间所对应的值就是第k小了 87 while(l<r){ 88 int mid = (l+r)>>1; 89 if(c[lson[urt]] + c[lson[vrt]] - c[lson[frt]]-c[lson[lcart]]>=k){ 90 r = mid; 91 urt = lson[urt]; 92 vrt = lson[vrt]; 93 frt = lson[frt]; 94 lcart = lson[lcart]; 95 } 96 else 97 { 98 l = mid+1; 99 k -= c[lson[urt]] + c[lson[vrt]] - c[lson[frt]]-c[lson[lcart]]; 100 urt = rson[urt]; 101 vrt = rson[vrt]; 102 frt = rson[frt]; 103 lcart = rson[lcart]; 104 } 105 } 106 return l; 107 } 108 void init() { 109 for(int k=0;k+1<25; ++k){ 110 for(int v = 0;v<=n;++v){ 111 if(fa[v][k]<0) 112 fa[v][k+1] = -1; 113 else 114 fa[v][k+1] = fa[fa[v][k]][k]; 115 } 116 } 117 } 118 119 int lca(int u, int v){ 120 if(depth[u] < depth[v]) 121 swap(u,v); 122 123 int tmp = depth[u] - depth[v]; 124 for(int i=25;i>=0;--i) 125 if(tmp &(1<<i)) 126 u = fa[u][i]; 127 if(u==v) return u; 128 for(int i=25;i>=0;--i){ 129 if(fa[u][i]!=fa[v][i]){ 130 u = fa[u][i]; 131 v = fa[v][i]; 132 } 133 } 134 return fa[u][0]; 135 136 } 137 int main(int argc, const char * argv[]) { 138 int u,v,k; 139 while(scanf("%d%d",&n,&q)!=EOF){ 140 total = dfs_clock = 0; 141 for(int i=1;i<=n;++i){ 142 scanf("%d",&a[i]); 143 b[i] = a[i]; 144 } 145 memset(head,-1,sizeof(head)); 146 for(int i=1;i<n;++i){ 147 scanf("%d%d",&u,&v); 148 addEdge(u,v); 149 addEdge(v,u); 150 } 151 addEdge(0,1); 152 addEdge(1,0); 153 initHash(); 154 iid[0] = t[0] = build(1,m); 155 memset(fa,-1,sizeof(fa)); 156 dfs(0,0,1); 157 158 init(); 159 while(q--){ 160 scanf("%d%d%d",&u,&v,&k); 161 int lc = lca(u,v); 162 int f = fa[lc][0]; 163 printf("%d\n",b[query(iid[u],iid[v],iid[lc],iid[f],k)]); 164 } 165 } 166 167 return 0; 168 }