/*
*
* 先将数组里面每个数进行离散化
* 用可持久化线段树维护每一个数值出现的次数,从左到右每增加一个数值,线段树增加一个版本,
* 对于一个区间[0, M]而言,可以求出任何一个版本下,离散化后数值在[0, M]中的数字的总个数
* 题目要求第L个数到第R个数中第K小的数值是多少,可以在第L-1个版本和第R版本分别求区间[0,M]
* 中的数值总数,两者的差就是原来的第L个数到第R个数, 离散化后的数值落在数值区间[0, M]的
* 总个数,如果这个个数刚好就是K,那就等价于找到了一个合法的M,用二分法查找最小的一个合法的M
* 再把M的数值映射回原始的数值即可
*
*/
#include <stdio.h>
#include <algorithm>
#include <set>
#include <map>
#include <string.h>
using namespace std;
struct Node {
int start; // 区间开始位置
int end; // 区间结束位置
int left_idx; // 左子节点的下标
int right_idx; // 右子节点的下标
int cnt; // 区间中出现的数值的总个数
}__global_nodes[100005*20];
int __root_entry[100005]; // 每个版本的入口root节点id, 初始化线段树时候,线段树的版本就是0,每修改一次单点数据,版本号递增
class SegmentTree {
private:
Node* __nodes; // 节点数组
int __n; // 区间为0到n-1
int __node_buf_idx; // 当前能够取用的节点缓存的下标
int __cur_max_version; // 当前的最大版本号,版本号从0开始
// 更新单个位置的数值
// node_idx是上一个版本对应的节点的id, new_node_idx是当前最新版本的节点对应的id
void __update_single(int node_idx, int new_node_idx, int pos, int val) {
//printf("start = %d, end = %d\n", __nodes[node_idx].start, __nodes[node_idx].end);
Node& node = __nodes[node_idx];
Node& new_node = __nodes[new_node_idx];
new_node.start = node.start;
new_node.end = node.end;
if (new_node.start == new_node.end) {
new_node.left_idx = new_node.right_idx = -1;
new_node.cnt += val;
return;
}
int mid = (new_node.start + new_node.end) >> 1;
if (pos <= mid) {
// 新添加左节点,右节点复用
new_node.left_idx = __node_buf_idx++;
new_node.right_idx = node.right_idx;
__update_single(node.left_idx, new_node.left_idx, pos, val);
} else {
// 新添加右节点,左节点复用
new_node.left_idx = node.left_idx;
new_node.right_idx = __node_buf_idx++;
__update_single(node.right_idx, new_node.right_idx, pos, val);
}
new_node.cnt = __nodes[new_node.left_idx].cnt + __nodes[new_node.right_idx].cnt;
}
// 获取区间统计信息
int __get_val(int node_idx, int start, int end) {
Node& node = __nodes[node_idx];
if (node.start == start && node.end == end) {
return node.cnt;
}
int mid = (node.start + node.end) >> 1;
if (end <= mid) {
return __get_val(node.left_idx, start, end);
} else if (start >= mid+1) {
return __get_val(node.right_idx, start, end);
} else {
int val1 = __get_val(node.left_idx, start, mid);
int val2 = __get_val(node.right_idx, mid+1, end);
return val1 + val2;
}
}
void __build_tree(int cur_id, int start, int end) {
__nodes[cur_id].start = start;
__nodes[cur_id].end = end;
__nodes[cur_id].cnt = 0;
if (start == end) {
__nodes[cur_id].left_idx = -1;
__nodes[cur_id].right_idx = -1;
} else {
int mid = (start + end) / 2;
__nodes[cur_id].left_idx = __node_buf_idx++;
__build_tree(__nodes[cur_id].left_idx, start, mid);
__nodes[cur_id].right_idx = __node_buf_idx++;
__build_tree(__nodes[cur_id].right_idx, mid+1, end);
}
}
public:
SegmentTree(int n, Node* pnodes) {
__n = n;
__nodes = pnodes;
__cur_max_version = 0;
__root_entry[0] = 0;
__node_buf_idx = 0;
__build_tree(__node_buf_idx++, 0, __n);
}
// 更新单个数据接口, 每更新一次,增加一个版本
void update_single(int pos, int val) {
__cur_max_version += 1;
__root_entry[__cur_max_version] = __node_buf_idx++;
__update_single(__root_entry[__cur_max_version-1], __root_entry[__cur_max_version], pos, val);
}
// 获取区间统计数据接口
int get_val(int version, int start, int end) {
return __get_val(__root_entry[version], start, end);
}
};
int val_list[100005];
int main(void) {
//freopen("/Users/grh/Programming/CLionProjects/Test/data.txt", "r", stdin);
int n, m, val;
scanf("%d %d", &n, &m);
set<int> all_vals;
map<int, int> val2idx; // 离散化后数值到下标的映射
map<int ,int> idx2val; // 离散化后下标到数值的映射
for (int i = 0; i < n; i++) {
scanf("%d", &val);
val_list[i] = val;
all_vals.insert(val);
}
int idx = 0;
for (int val : all_vals) {
val2idx[val] = idx;
idx2val[idx] = val;
idx++;
}
int val_num = all_vals.size();
SegmentTree tree(val_num, __global_nodes);
for (int i = 0; i < n; i++) {
tree.update_single(val2idx[val_list[i]], 1); // 数值计数增加1
}
int start, end, k;
int l, r, mid, cnt, ans;
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &start, &end, &k);
l = 0;
r = val_num-1;
ans = -1;
while (l <= r) {
mid = l + (r-l)/2;
cnt = tree.get_val(end, 0, mid) - tree.get_val(start-1, 0, mid);
if (cnt >= k) {
ans = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
printf("%d\n", idx2val[ans]);
}
}