#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
vector<int > b;
struct node
{
int sum;//表示当前区间范围内的数出现了多少次。
int l, r;//表示当前节点的左右儿子节点对应的节点下标。
}tr[N * 40];
int num = 0;//表示当前节点的空间用到了多少。
int root[N];//表示当当前版本对应的根节点的编号。
int a[N];
void pushup(int u)//用来用子节点的值来更新父节点的值。
{
tr[u].sum = tr[tr[u].l].sum + tr[tr[u].r].sum;
}
int fed(int x)
{
return lower_bound(b.begin(), b.end(), x) - b.begin() + 1;
}
void build(int u, int l, int r)//建树。
{
if (l == r)
{
tr[u].sum = 0;
}
else
{
int mid = l + r >> 1;
tr[u].l = ++num;//类似于二叉树的空间的申请
tr[u].r = ++num;//同二叉树的申请。
build(tr[u].l, l, mid);
build(tr[u].r, mid + 1, r);
}
}
//插入操作。
void insert(int pre ,int u, int l, int r, int x)
{
if (l == r)
{
tr[u].sum++;
}
else
{
tr[u] = tr[pre];
int mid = l + r >> 1;
if (x <= mid)
{
tr[u].l = ++num;
insert(tr[pre].l, tr[u].l, l, mid , x);
}
else
{
tr[u].r = ++num;
insert(tr[pre].r, tr[u].r, mid + 1, r, x);
}
pushup(u);
}
}
//查询操作。
int query(int pre, int now, int l, int r, int k)
{
if (l == r)return l;
else
{
int mid = l + r >> 1;
int ans1 = tr[tr[now].l].sum - tr[tr[pre].l].sum;
if (ans1 >= k)return query(tr[pre].l, tr[now].l, l, mid, k);
else return query(tr[pre].r, tr[now].r, mid + 1, r, k - ans1);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
root[0] = 1;
num++;
build(1, 1, n);
for (int i = 1; i <= n; i++)
{
cin >> a[i];
b.push_back(a[i]);
}
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
for (int i = 1; i <= n; i++)
{
root[i] = ++num;
insert(root[i - 1], root[i], 1, n, fed(a[i]));
}
int l, r, k;
while (m--)
{
cin >> l >> r >> k;
cout << b[query(root[l - 1], root[r], 1, n, k) - 1]<< endl;
}
}