/*
分析:
划分树果题(第一道划分树囧~)。
昨晚看了划分树的知识,不过时间不够了,就没有实现,
今儿敲了下,还行~。因为在query操作中,我们真正使用的是
差值,所以toleft数组么必要非得记录i所属区间中进入左儿子
区间的元素数量。
2013-03-29
*/
分析:
划分树果题(第一道划分树囧~)。
昨晚看了划分树的知识,不过时间不够了,就没有实现,
今儿敲了下,还行~。因为在query操作中,我们真正使用的是
差值,所以toleft数组么必要非得记录i所属区间中进入左儿子
区间的元素数量。
2013-03-29
*/
#include"iostream"
#include"cstdio"
#include"cstring"
#include"algorithm"
using namespace std;
const int N=20;
const int M=100011;
int n,m;
int tr[N][M],toleft[N][M],sorted[M];
void build(int l,int r,int k)
{
if(l==r) return ;
int i;
int ln,rn,equ,mid;
mid=(l+r)>>1;equ=0;ln=l;rn=mid+1;
for(i=mid;i>=l;i--)
{
if(sorted[i]==sorted[mid]) equ++;
else break;
}
for(i=l;i<=r;i++)
{
toleft[k][i]=toleft[k][i-1];
if(tr[k][i]<sorted[mid])
{
tr[k+1][ln++]=tr[k][i];
toleft[k][i]++;
}
else if(tr[k][i]==sorted[mid])
{
if(equ) {tr[k+1][ln++]=tr[k][i];equ--;toleft[k][i]++;}
else tr[k+1][rn++]=tr[k][i];
}
else tr[k+1][rn++]=tr[k][i];
}
build(l,mid,k+1);
build(mid+1,r,k+1);
}
int query(int a,int b,int t,int l,int r,int k)
{
if(l==r) return tr[k][l];
int mid,p,pp;
mid=(l+r)>>1;
p=toleft[k][a-1]-toleft[k][l-1]; //[l,a)划分到左儿子的数量
pp=toleft[k][b]-toleft[k][a-1]; //[a,b]划分到左儿子的数量
if(pp>=t) return query(l+p,l+p+pp-1,t,l,mid,k+1);
else
{
int z,zz;
z=a-l-p; //[l,a)划分到右儿子的数量
zz=b-a+1-pp; //[a,b]划分到右儿子的数量
return query(mid+z+1,mid+z+zz,t-pp,mid+1,r,k+1);
}
}
int main()
{
int T;
int i;
int a,b,t;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) {scanf("%d",&tr[0][i]);sorted[i]=tr[0][i];}
sort(sorted+1,sorted+n+1);
toleft[0][0]=0;
build(1,n,0);
while(m--)
{
scanf("%d%d%d",&a,&b,&t);
printf("%d\n",query(a,b,t,1,n,0));
}
}
return 0;
}