静态主席树

【转】主席树:对于序列的每一个前缀建一棵以序列里的值为下标的线段树(所以要先离散化),记录该前缀序列里出现的值的次数;记离散后的标记为1~n; (下面值直接用1~n代替;) 

对于区间[x,y]的第k大的值,那么从root[x-1],root[y]开始,t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示区间[x,y]内值在[1,mid]的个数 先判断t是否大于K。

如果t大于k,那么说明在区间[x,y]内存在[1,mid]的数的个数大于k,也就是第k大的值在[1,mid]中,否则在[mid+1,r]中;

这样我们依次同时从root[x-1],root[y]往下走当l==r时 第k大的值就是离散后标记为l的值

;如果每棵线段都建完整的化,n*(n<<2)肯定会mle,我们发现对于前缀[1,i]和前缀[1,i+1]的线段树,如果b[i+1]<=mid (b[i+1]表示a[i+1]离散后的标记)那么线段树i和线段树i+1的左边是完全相同的,根本不需要再建,只需要用指针指一下就好;那么对于一棵新的线段树其实我们最多要建的节点数为log(n);nlog(n)的节点数还是可以忍受的;

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cmath>
 6 using namespace std;
 7 const int maxn = 10000 + 10;
 8 const int maxnn = 100 * maxn;
 9 int n, Q, ms, tot;
10 int root[maxn], A[maxn], ls[maxnn], rs[maxnn], s[maxnn];
11 int num[maxn], hash[maxn];
12 int find(int x){
13     int L = 1, R = tot, M;
14     while(L <= R){
15         M = L + R >> 1;
16         if(hash[M] < x) L = M + 1;
17         else R = M - 1;
18     }
19     return L;
20 }
21 void build(int x, int& y, int L, int R, int v){
22     s[y = ++ ms] = s[x] + 1;
23     if(L == R) return;
24     ls[y] = ls[x]; rs[y] = rs[x];
25     int M = L + R >> 1;
26     if(v <= M) build(ls[x], ls[y], L, M, v);
27     else build(rs[x], rs[y], M + 1, R, v);
28     return ;
29 }
30 int query(int x, int y, int L, int R, int k){
31     if(L == R) return L;
32     int M = L + R >> 1, kth = s[ls[y]] - s[ls[x]];
33     if(kth >= k) return query(ls[x], ls[y], L, M, k);
34     else return query(rs[x], rs[y], M + 1, R, k - kth);
35 }
36 void read(int &x){
37     x = 0; int sig = 1; char ch = getchar();
38     while(!isdigit(ch)) { if(ch == '-') sig = -1; ch = getchar(); }
39     while(isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
40     x *= sig; return ;
41 }
42 void init(){
43     read(n); read(Q);
44     for(int i = 1; i <= n; i ++) read(A[i]), num[i] = A[i];
45     sort(num + 1, num + n + 1); hash[++ tot] = num[1];
46     for(int i = 2; i <= n; i ++) if(num[i] != num[i - 1]) hash[++ tot] = num[i];
47     for(int i = 1; i <= n; i ++) build(root[i - 1], root[i], 1, tot, find(A[i]));
48     return ;
49 }
50 void work(){
51     int _i, _j, _k;
52     while(Q --){
53         read(_i); read(_j); read(_k);
54         printf("%d
", hash[query(root[_i - 1], root[_j], 1, tot, _k)]);
55     }
56     return ;
57 }
58 void print(){
59 
60     return ;
61 }
62 int main(){
63     init();
64     work();
65     print();
66     return 0;
67 }
原文地址:https://www.cnblogs.com/chxer/p/4394720.html