18.10.22 POJ 2104 K-th Number(二分+线段树+离散化)
描述
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.输入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).输出For each question output the answer to it --- the k-th number in sorted a[i...j] segment
.样例输入
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
样例输出
5
6
3
提示
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
来源
Northeastern Europe 2004, Northern Subregion
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <stack> 5 #include <string> 6 #include <math.h> 7 #include <queue> 8 #include <stdio.h> 9 #include <string.h> 10 #include <vector> 11 #include <fstream> 12 #include <set> 13 #include<map> 14 #define l(rt) rt*2 15 #define r(rt) rt*2+1 16 #define mid(l,r) (l+r)/2 17 18 using namespace std; 19 const int maxn = 100005; 20 int n, m,num[maxn],b[maxn]; 21 struct number { 22 int val, id; 23 bool operator <(number a) { 24 return val < a.val; 25 } 26 }; 27 number _num[maxn]; 28 struct node { 29 vector<int> va; 30 int l, r; 31 }tree[4*maxn]; 32 33 void build(int rt,int l,int r) { 34 tree[rt].l = l, tree[rt].r = r; 35 if (l == r) 36 { 37 tree[rt].va.push_back(b[l]); 38 return; 39 } 40 build(l(rt), l, mid(l, r)); 41 build(r(rt), mid(l, r) + 1, r); 42 int i = 0, j = 0, sizer = tree[r(rt)].va.size(), sizel = tree[l(rt)].va.size(); 43 while (i != sizel || j != sizer) { 44 if (i != sizel && j != sizer) { 45 if (tree[l(rt)].va[i] <= tree[r(rt)].va[j]) 46 tree[rt].va.push_back(tree[l(rt)].va[i++]); 47 else 48 tree[rt].va.push_back(tree[r(rt)].va[j++]); 49 } 50 if (i == sizel) 51 while (j != sizer) 52 tree[rt].va.push_back(tree[r(rt)].va[j++]); 53 if (j == sizer) 54 while (i != sizel) 55 tree[rt].va.push_back(tree[l(rt)].va[i++]); 56 } 57 return; 58 } 59 60 int query(int rt, int l, int r, int x) {//小于等于x的个数 61 if (tree[rt].l == l && tree[rt].r == r) 62 return upper_bound(tree[rt].va.begin(), tree[rt].va.end(), x)-tree[rt].va.begin(); 63 int midn = mid(tree[rt].r, tree[rt].l); 64 if (l > midn) 65 return query(r(rt), l, r, x); 66 else if (r <= midn) 67 return query(l(rt), l, r, x); 68 else 69 return query(l(rt), l, midn, x) + query(r(rt), midn + 1, r, x); 70 } 71 72 void solve(int l, int r, int k) { 73 int res; 74 int s = 1, e = n+1; 75 while (s<e) { 76 int x = s + (e - s) / 2; 77 res = query(1, l, r, x); 78 if (res >= k)e = x; 79 else 80 s = x + 1; 81 } 82 printf("%d\n", num[s]); 83 } 84 85 void init() { 86 scanf("%d%d", &n, &m); 87 for (int i = 1; i <= n; i++) 88 { 89 scanf("%d", &num[i]); 90 _num[i].val = num[i]; 91 _num[i].id = i; 92 } 93 sort(_num + 1, _num + n + 1); 94 for (int i = 1; i <= n; i++) 95 b[_num[i].id] = i; 96 build(1,1, n); 97 sort(num + 1, num + n + 1); 98 while (m--) { 99 int x, y, k; 100 scanf("%d%d%d", &x, &y, &k); 101 solve(x, y, k); 102 } 103 } 104 105 int main() 106 { 107 init(); 108 return 0; 109 }
每个星期一都是意识模糊的一天
查了下,还有一种做法是主席树,很有意思,准备之后看一下
思路:
二分查找答案使得尝试的这个数x在所考察区间内,正好有k个数字小于等于它
线段树的作用是得到区间内小于等于x的数的个数
离散化是加快速度
这个实现超烂,又臭又长