题目链接:http://poj.org/problem?id=2104
题目分析:该问题给定一段区间中的值,再给定一段查询区间[ql, qr],需要给出该查询区间中的值在排序后的第K大的值;
使用划分树即可解决该问题;划分树的建树的复杂度为O(NlogN),查询一个区间的第K大值的复杂度为O(logN);
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int MAX_N = 100000 + 10; int sorted[MAX_N]; int to_left[20][MAX_N]; int tree[20][MAX_N]; void Build(int l, int r, int deep) { if (l == r) return; int mid = (l + r) >> 1; int lc_same = mid - l + 1; int l_pos = l, r_pos = mid + 1; for (int i = l; i <= r; ++i) { if (tree[deep][i] < sorted[mid]) lc_same--; } for (int i = l; i <= r; ++i) { if (tree[deep][i] < sorted[mid]) tree[deep + 1][l_pos++] = tree[deep][i]; else if (tree[deep][i] == sorted[mid] && lc_same > 0) { lc_same--; tree[deep + 1][l_pos++] = tree[deep][i]; } else tree[deep + 1][r_pos++] = tree[deep][i]; to_left[deep][i] = to_left[deep][l - 1] + l_pos - l; } Build(l, mid, deep + 1); Build(mid + 1, r, deep + 1); } int Query(int l, int r, int ql, int qr, int deep, int k) { if (l == r) return tree[deep][l]; int mid = (l + r) >> 1; int cnt = to_left[deep][qr] - to_left[deep][ql - 1]; if (cnt >= k) { int new_ql = l + to_left[deep][ql - 1] - to_left[deep][l - 1]; int new_qr = new_ql + cnt - 1; return Query(l, mid, new_ql, new_qr, deep + 1, k); } else { int new_qr = qr + to_left[deep][r] - to_left[deep][qr]; int new_ql = new_qr - (qr - ql - cnt); return Query(mid + 1, r, new_ql, new_qr, deep + 1, k - cnt); } } int main() { int n, query_times; scanf("%d %d", &n, &query_times); for (int i = 1; i <= n; ++i) { scanf("%d", &tree[0][i]); sorted[i] = tree[0][i]; } sort(sorted + 1, sorted + n + 1); Build(1, n, 0); for (int i = 0; i < query_times; ++i) { int ql, qr, k, ans; scanf("%d %d %d", &ql, &qr, &k); ans = Query(1, n, ql, qr, 0, k); printf("%d\n", ans); } return 0; }
时间: 2024-10-03 23:53:29