树上第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
",b[query(iid[u],iid[v],iid[lc],iid[f],k)]);
164         }
165     }
166 
167     return 0;
168 }
原文地址:https://www.cnblogs.com/justPassBy/p/4831470.html