题目背景
这是个非常经典的主席树入门题——静态区间第 k 小
数据已经过加强,请使用主席树。同时请注意常数优化
题目描述
如题,给定 n 个整数构成的序列,将对于指定的闭区间查询其区间内的第 k 小值。
输入格式
第一行包含两个正整数 n,m,分别表示序列的长度和查询的个数。
第二行包含 n 个整数,表示这个序列各项的数字。
接下来 m 行每行包含三个整数 l,r,k , 表示查询区间 [l,r] 内的第 k 小值。
输出格式
输出包含 k 行,每行一个整数,依次表示每一次查询的结果
输入输出样例
输入 #1复制
5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
输出 #1复制
6405
15770
26287
25957
26287
说明/提示
数据范围:
对于 20% 的数据满足:1≤n,m≤10
扫描二维码关注公众号,回复:
8922812 查看本文章
对于 50% 的数据满足:1≤n,m≤103
对于 80% 的数据满足:1≤n,m≤105
对于 100% 的数据满足:1≤n,m≤2×105
对于数列中的所有数 ai,均满足 −109≤ai≤109
样例数据说明:
n=5,数列长度为 5,数列从第一项开始依次为[25957,6405,15770,26287,26465]
第一次查询为[2,2]区间内的第一小值,即为 6405
第二次查询为 [3,4] 区间内的第一小值,即为 15770
第三次查询为 [4,5] 区间内的第一小值,即为 26287
第四次查询为 [1,2] 区间内的第二小值,即为 25957
第五次查询为 [4,4] 区间内的第一小值,即为 26287
题解
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int cnt, a[maxn], root[maxn];
struct node { int l, r, sum; } tree[maxn * 40];
vector<int> v;
inline const int read()
{
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
return x * f;
}
inline int getid(int x)
{
return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
void update(int l, int r, int p, int pre, int& now)
{
tree[now = ++cnt] = tree[pre];
tree[now].sum++;
if (l == r) return;
int mid = (l + r) >> 1;
if (p <= mid) update(l, mid, p, tree[pre].l, tree[now].l);
else update(mid + 1, r, p, tree[pre].r, tree[now].r);
}
int query(int l, int r, int k, int L, int R)
{
if (l == r) return l;
int mid = (l + r) >> 1;
int nl = tree[tree[R].l].sum - tree[tree[L].l].sum;
return k <= nl ? query(l, mid, k, tree[L].l, tree[R].l) : query(mid + 1, r, k - nl, tree[L].r, tree[R].r);
}
int main()
{
int n = read(), m = read();
for (int i = 1; i <= n; i++) v.push_back(a[i] = read());
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; i++) update(1, n, getid(a[i]), root[i - 1], root[i]);
while (m--)
{
int l = read(), r = read(), k = read();
printf("%d\n", v[query(1, n, k, root[l - 1], root[r]) - 1]);
}
return 0;
}