1 #include<cstdio>
2 #include<algorithm>
3 #include<vector>
4 using namespace std;
5 const int maxn=1e5+10;
6 int n,m,cnt,root[maxn];
7 int b[maxn],a[maxn];
8 struct node{int l,r,sum;}T[maxn*40];
9 void update(int l,int r,int &x,int y,int pos)
10 {
11 //这里&的这种用法我不太清楚,大概就是能值传会root[];
12 //这里T[++cnt]的值先从root[y](也就是上一颗树)传过来,然后再
13 //多拉出几个节点,去连接与之前的树相关的节点(同样是传值这一步操作)
14 T[++cnt]=T[y],T[cnt].sum++,x=cnt;
15 if(l==r) return;
16 int mid=(l+r)/2;
17 if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);
18 else update(mid+1,r,T[x].r,T[y].r,pos);
19 }
20 int query(int l,int r,int x,int y,int pos)
21 {
22 if(l==r) return l;
23 int mid=l+r>>1;
24 //这里如果sum>=pos,证明第pos大的值就在左边了,所以只需要枚举左边;
25 //否则枚举右边;
26 int sum=T[T[y].l].sum-T[T[x].l].sum;
27 if(sum>=pos) return query(l,mid,T[x].l,T[y].l,pos);
28 //右边的操作与左边大致相同,但是需要pos-sum,把前面的数去掉,
29 //因为右数是从1重新开始计数的。
30 else return query(mid+1,r,T[x].r,T[y].r,pos-sum);
31 }
32 int main()
33 {
34 scanf("%d%d",&n,&m);
35 for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
36 sort(b+1,b+1+n);
37 //离散化,为什么要离散化呢。因为主席树需要开的内存很大,
38 //离散化能降低内存;
39 int t=unique(b+1,b+1+n)-b-1;
40 for(int i=1;i<=n;i++){
41 //取出离散化后的值;
42 int tmp=lower_bound(b+1,b+1+t,a[i])-b;
43 update(1,n,root[i],root[i-1],tmp);
44 }
45 for(int i=1;i<=m;i++){
46 int x,y,k;
47 scanf("%d%d%d",&x,&y,&k);
48 //求出query后,再放进b数组,还原为之前的值。
49 printf("%d\n",b[query(1,n,root[x-1],root[y],k)]);
50 }
51 return 0;
52 }