题意:
第一行两个正整数N,M。
第二行N个数,表示序列A1,A2,...,AN。
紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj中第k小的数等于多少。
解法:主席树。
先离散,然后对于每一个前缀开一棵权值线段树Ri,用来计算在A1..Ai的区间内某个数的名次。
然后线段树是可以对应点相减的,即Rj-R(i-1)可以计算Ai..Aj的区间内某个数的名次。
线段树上二分即可。
1 #include <algorithm> 2 #include <stdio.h> 3 #include <utility> 4 const int N = 100001; 5 6 typedef struct Node *Tree; 7 struct Node { 8 int l, r, size; 9 Tree ch[2]; 10 } nodes[N * 20], *now = nodes, *root[N]; 11 void build(Tree &tr, register int l, register int r) { 12 tr = now++; 13 tr->l = l; 14 tr->r = r; 15 tr->size = 0; 16 if(l == r) tr->ch[0] = tr->ch[1] = 0; 17 else build(tr->ch[0], l, l + r >> 1), build(tr->ch[1], l + r + 2 >> 1, r); 18 } 19 void insert(Tree &tr, int pos) { 20 *now = *tr; 21 tr = now++; 22 ++tr->size; 23 if(tr->l != tr->r) insert(tr->ch[pos >= tr->ch[1]->l], pos); 24 } 25 int query(Tree pre, Tree end, register int k) { 26 if(pre->l == pre->r) return pre->l; 27 register int s = end->ch[0]->size - pre->ch[0]->size; 28 if(k <= s) return query(pre->ch[0], end->ch[0], k); 29 else return query(pre->ch[1], end->ch[1], k - s); 30 } 31 32 std::pair<int, int> a[N]; 33 int n, m, no[N]; 34 int main() { 35 scanf("%d%d", &n, &m); 36 for(int i = 1; i <= n; ++i) { 37 scanf("%d", &a[i].first); 38 a[i].second = i; 39 } 40 std::sort(a + 1, a + n + 1); 41 for(int i = 1; i <= n; ++i) { 42 no[a[i].second] = i; 43 } 44 build(root[0], 1, n); 45 for(int i = 1; i <= n; ++i) { 46 root[i] = root[i - 1]; 47 insert(root[i], no[i]); 48 } 49 while(m--) { 50 int i, j, k; 51 scanf("%d%d%d", &i, &j, &k); 52 printf("%d\n", a[query(root[i - 1], root[j], k)].first); 53 } 54 return 0; 55 }