分桶法:把一排物品或者平面分成桶,每个桶饭分别维护自己的内部信息,以达到高效计算的目的的方法。
平方分割:把一排n个元素中每√n个元素分在一个桶内进行维护的方法,使对区间操作的时间复杂度降为O(√n)。
类似线段树哦。
给定一个n个整数的数列a1, a2, a3, ..., an和m个三元组表示的查询。对于每个查询(i, j, k)输出ai, a(i+1), ..., aj的升序排列中的第k个数。(n <= 100000, m <= 5000)
输入 n = 7, m = 3 a = {1, 5, 2, 6, 3, 7, 4} {(2, 5, 3), (4, 4, 1), (1, 7, 3)}
输出 5 6 3
最容易想到的是把给定的区间进行排序,然后直接求出第k个数,但m<=5000,而且n<=100000,这样会超时的啦。
可以这样想,如果x为查询区间中的第k个数,那么他会有:
1)在区间中不超过x的数不少于k个(有可能区间中有多个x)
2)在区间中小于x的数有不到k个
所以可以使用二分来对排好序的b[]数列(对a[]排好序后的数组)进行查找x是否满足上面的条件,直到找到完成查找哦。
判断x是否满足:如果查询区间都落在一个桶的范围上,那么就拿x和a[i]到a[j]一个个比较,记录k的值; 如果查询区间在多个桶之间,那么第一个桶和最后一个桶只需遍历,其它的直接使用upper_bound(其它的桶里的元素都排好序了)。
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
#define MAX_N 100005
const int BUCKETS_SIZE = 1000;
int a[MAX_N], b[MAX_N];
int s[5005], e[5005], pos[5005];
vector<int> buckets[MAX_N / BUCKETS_SIZE];
int n, m;
int main() {
int i;
int l, r, k, tl, tr, tk;
int left, right, mid;
int x, tmp;
while (scanf("%d%d", &n, &m) != EOF && n || m) {
for (i = 0; i <= n / BUCKETS_SIZE; i++) {
buckets[i].clear();
}
// 输入数列并入桶
for (i = 1; i <= n; i++) {
scanf("%d", &a[i]);
buckets[i / BUCKETS_SIZE].push_back(a[i]);
b[i] = a[i];
}
// 输入三元组
for (i = 0; i < m; i++) {
scanf("%d%d%d", &s[i], &e[i], &pos[i]);
}
// 排序,剩下一个桶可以不排序
sort(b + 1, b + n + 1);
for (i = 0; i < n / BUCKETS_SIZE; i++) {
sort(buckets[i].begin(), buckets[i].end());
}
for (i = 0; i < m; i++) {
l = s[i], r = e[i], k = pos[i];
left = 1, right = n + 1;
while (left < right) {
mid = (left + right) / 2;
x = b[mid];
tl = l, tr = r, tk = 0;
// 在同一个桶中,遍历区间
while (tl <= tr && tl % BUCKETS_SIZE != 0) {
if (a[tl++] <= x) {
++tk;
}
}
while (tl <= tr && tr % BUCKETS_SIZE != 0) {
if (a[tr--] <= x) {
++tk;
}
}
// 区间不全在一个桶中,可以从排好序的同桶中upper_bound取得
while (tl <= tr) {
tmp = tl / BUCKETS_SIZE;
tk += upper_bound(buckets[tmp].begin(), buckets[tmp].end(), x) - buckets[tmp].begin();
tl += BUCKETS_SIZE;
}
if (k <= tk) {
right = mid;
} else {
left = mid + 1;
}
}
printf("%d\n", b[right]);
}
}
return 0;
}
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
7 4
9 3 7 4 5 3 8
1 7 7
1 7 4
1 7 5
1 7 3
7 4
9 3 7 4 5 3 8
2 5 2
7 7 1
3 6 2
1 7 7