You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.7 KiB

2 years ago
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
//快读
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 ^ 48);
ch = getchar();
}
return x * f;
}
const int N = 2e5 + 10;
int n, m;
int a[N];
vector<int> ys;
struct Node {
int l, r, cnt;
} tr[N << 5];
int root[N], idx;
int find(int x) {
return lower_bound(ys.begin(), ys.end(), x) - ys.begin();
}
//经典的主席树插入
void insert(int &u, int l, int r, int x) {
tr[++idx] = tr[u]; //新开一个节点idx++,将新节点指向旧的tr[u]
u = idx; //因为是引用为了回传正确值需要u=idx-1
tr[u].cnt++; //新节点的cnt因为多插入了一个数字所以个数+1,这样处理的话省去了pushup
if (l == r) return; //如果已经到了叶子节点,上面的操作就足够了,可以直接返回,否则需要继续向下递归
int mid = (l + r) >> 1;
if (x <= mid)
insert(tr[u].l, l, mid, x); //因为tr[u]进入本函数时最先把旧的复制过来所以tr[u].l也是上一个版本的左儿子节点
else
insert(tr[u].r, mid + 1, r, x);
}
int query(int p, int q, int l, int r, int k) {
if (l == r) return l;
int mid = (l + r) >> 1;
int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
if (k <= cnt)
return query(tr[p].l, tr[q].l, l, mid, k);
else
return query(tr[p].r, tr[q].r, mid + 1, r, k - cnt);
}
int main() {
//文件输入输出
#ifndef ONLINE_JUDGE
freopen("P3834.in", "r", stdin);
#endif
n = read(), m = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
ys.push_back(a[i]);
}
//数据范围太大直接建线段树会MLE但是比较稀疏可以离散化后用相对应的序号数据量就小了
sort(ys.begin(), ys.end());
ys.erase(unique(ys.begin(), ys.end()), ys.end());
// 0号版本没有内容时主席树是不需要进行build的,强行build时可能会有部分测试点TLE
// 0号版本有内容时主席树是需要build的不build初始值无法给上
//主席树的数字增加每增加一个就相当于增加了一个版本root[i]记录了版本i的根节点
for (int i = 1; i <= n; i++) {
root[i] = root[i - 1];
insert(root[i], 0, ys.size() - 1, find(a[i]));
}
while (m--) {
int l, r, k;
l = read(), r = read(), k = read();
printf("%d\n", ys[query(root[l - 1], root[r], 0, ys.size() - 1, k)]);
}
return 0;
}