K-th Number
Description
You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
For each question output the answer to it --- the k-th number in sorted a[i...j] segment.
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
题解:这题有很多种写法。归并树,故名思义,就是用树形结构来存归并排序的相关信息。这里用到的是线段树,因为归并排序划分子序列的方式和线段树划分子序列的方式相同,
既划分(l,r)区间,子区间分别为(l,mid)和(mid+1,r)。树的每个节点对应了一段区间,存的是这段区间排好序的序列。如何排序?看归并树的名字,在合并子区间的时候
用上归并排序就行了,既 Pushup函数 。由于合并是自底向上的,所以第一层就是整个序列排好序的样子。而查询就是枚举第一层序列的数看是否满足要求,因为有序,二分就有
了用武之地。对于要查询的区间,在归并树中有着对应的节点(节点就是一段区间),且已经排好序。那么用lower_bound可以方便的求出在这个区间有多少个小于key的数。
注意:实现的时候要仔细了解lower_bound的特点。统计的是小于key的个数。
1 #pragma warning(disable:4996) 2 #include<bitset> 3 #include<string> 4 #include<cstdio> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 using namespace std; 9 typedef long long ll; 10 11 const int maxn = 100005; 12 13 int n, q; 14 int Tree[20][maxn], a[maxn]; 15 16 void Pushup(int l, int mid, int r, int deep) { 17 int i = l, j = mid + 1, k = l; 18 while (i <= mid && j <= r) { 19 if (Tree[deep + 1][i] <= Tree[deep + 1][j]) 20 Tree[deep][k++] = Tree[deep + 1][i++]; 21 else 22 Tree[deep][k++] = Tree[deep + 1][j++]; 23 } 24 while (i <= mid) Tree[deep][k++] = Tree[deep + 1][i++]; 25 while (j <= r) Tree[deep][k++] = Tree[deep + 1][j++]; 26 } 27 28 void Build(int l, int r, int deep) { 29 if (l == r) { 30 Tree[deep][l] = a[l]; 31 return; 32 } 33 int mid = (l + r) >> 1; 34 Build(l, mid, deep + 1); 35 Build(mid + 1, r, deep + 1); 36 Pushup(l, mid, r, deep); 37 } 38 39 40 int Query(int L, int R, int l, int r, int k, int deep) { 41 if (l > R || r < L) return 0; 42 if (l >= L && r <= R) return lower_bound(&Tree[deep][l], &Tree[deep][r] + 1, k) - &Tree[deep][l]; //用lower_bound时注意啦!!!!!! 43 44 int mid = (l + r) >> 1; 45 return Query(L, R, l, mid, k, deep + 1) + Query(L, R, mid + 1, r, k, deep + 1); 46 47 } 48 49 50 int Solve(int L, int R, int k) { 51 int l = 1, r = n + 1; //二分。。。。。别写挂了 52 for (int i = 1; i <= 30; i++) { 53 int mid = (l + r) >> 1; 54 int cnt = Query(L, R, 1, n, Tree[1][mid], 1); 55 if (cnt <= k) l = mid; 56 else r = mid; 57 } 58 return Tree[1][l]; 59 } 60 61 int main() 62 { 63 while (scanf("%d%d", &n, &q) != EOF) { 64 for (int i = 1; i <= n; i++) scanf("%d", &a[i]); 65 Build(1, n, 1); 66 67 for (int i = 1; i <= q; i++) { 68 int l, r, k; 69 scanf("%d%d%d", &l, &r, &k); 70 printf("%d\n", Solve(l, r, k - 1)); 71 } 72 } 73 return 0; 74 }