//動態開點可持久化權值線段樹
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
struct Segmentree
{
int ls,rs,sum;
}t[N<<5];
int rt[N],tot=0,n,m,a[N],b[N],p;//p含義為修改點
void build(int p,int l,int r)
{
p=++tot;
if(l==r) return;
int mid=(l+r)>>1;
build(t[p].ls,l,mid);
build(t[p].rs,mid+1,r);
}
int update(int root,int l,int r)
{
int op=++tot;
t[op].ls=t[root].ls,t[op].rs=t[root].rs,t[op].sum=t[root].sum+1;
if(l==r) return op;//左端點等于右端點,可以結束了
int mid=(l+r)>>1;
if(p<=mid) t[op].ls=update(t[op].ls,l,mid);
else t[op].rs=update(t[op].rs,mid+1,r);
return op;
}
long long query(int u,int v,int l,int r,int k)
{
long long ans=0;int mid=(l+r)>>1;
int x=t[t[v].ls].sum-t[t[u].ls].sum;
if(l==r) return l;
if(x>=k) ans=query(t[u].ls,t[v].ls,l,mid,k);
else ans=query(t[u].rs,t[v].rs,mid+1,r,k-x);//此處遞歸到右子樹需要減掉左子樹已經擁有的排名
return ans;
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1);
int len=unique(b+1,b+n+1)-b-1;//離散化,sort unique
build(rt[0],1,len);//建空樹
for(int i=1;i<=n;i++)
{
p=lower_bound(b+1,b+1+len,a[i])-b;
rt[i]=update(rt[i-1],1,len);//一個一個加上去
}
for(int i=1;i<=m;i++)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
long long ans=query(rt[l-1],rt[r],1,len,k);
//cout<<ans<<endl;
printf("%d\n",b[ans]);
}
return 0;
}