【转】主席树:对于序列的每一个前缀建一棵以序列里的值为下标的线段树(所以要先离散化),记录该前缀序列里出现的值的次数;记离散后的标记为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\n", 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 }
时间: 2024-10-24 04:27:06