#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL N = 200005;
struct tree {//L为左儿子, R为右儿子,sum为该节点的权值
int L;
int R;
LL sum;
}t[N << 5];//每个数离散化为1 - n后,储存在对应的下标
int cnt, tot, n, m, a[N], b[N], c[N], root[N];
int build(int l, int r)//初始化空树, 实际上没必要
{
int rt = ++cnt;
if(l == r) return rt;
int mid = l + r >> 1;
t[rt].L = build(l, mid);
t[rt].R = build(mid + 1, r);
return rt;
}
int change(int pre, int l, int r, int x)//建一棵只有logN个节点的线段树
{
int rt = ++cnt;//新建节点,下面动态开点
t[rt].L = t[pre].L;//继承前一棵树的左右子节点, 再做修改
t[rt].R = t[pre].R;
t[rt].sum = t[pre].sum + 1;//前一棵树相同位置上加一
if(l == r) return rt;
int mid = l + r >> 1;
if(x <= mid)
t[rt].L = change(t[pre].L, l, mid, x);//x在左子树,修改左子树
else
t[rt].R = change(t[pre].R, mid + 1, r, x);//x在右子树同理
return rt; //返回当前分配使用新节点的编号
}
int query(int x, int y, int l, int r, int k)
{
if(l >= r) return l;
int dta = t[t[y].L].sum - t[t[x].L].sum;//线段树相减,看左节点个数
int mid = l + r >> 1;
if(dta >= k) //左儿子大于等于k时,在左儿子第k个
return query(t[x].L, t[y].L, l, mid, k);
else //否则在右儿子第k - dta个
return query(t[x].R, t[y].R, mid + 1, r, k - dta);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
b[i] = a[i];
}
sort(b + 1, b + n + 1);
for(int i = 1; i <= n; i++)
{
if(b[i] != b[i - 1] || i == 1)//离散化去重
c[++tot] = b[i];
}
// root[0] = build(1, tot);
for(int i = 1; i <= n; i++)
{
int u = lower_bound(c + 1, c + tot + 1, a[i]) - c;
root[i] = change(root[i - 1], 1, tot, u);//建第i棵线段树,root[i]是对应的根节点
}
int u, v, w;
for(int i = 1; i <= m; i++)
{
cin >> u >> v >> w;
int t = query(root[u - 1], root[v], 1, tot, w);//第y棵线段树-第x-1棵线段树,是[x, y]的线段树
cout << c[t] << '\n';
}
return 0;
}