Input
The first line is the number of the test cases.
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
Output
For each test case, output m lines. Each line contains the kth big number.
Sample Input
1
10 1
1 4 2 3 5 6 7 8 9 0
1 3 2
Sample Output
2
【题意】
t组样例,有n个数,m个询问。
m个询问中有l,r,k;
询问在[l,r]区间中,第k大的数是多少。
【解法】
将n个数离散化(假设离散化后下标为1-t)后建立一颗区间为1-t的线段树,每个[x,x]都表示离散化后下标为x的数的个数。
用主席数记录每加入一个数后该线段树的变化。
最后求[l,r]区间的第k大时
两颗差值树中 左子树的size表示比当前根小的数的个数,如果左子树size>=k就在左子树中找,否则就去右子树中找k-左子树size的值。。。。。
呃,感觉解释不清。。意会意会吧。。上代码了。。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define N 100005
using namespace std;
int tree[N*25],lchild[N*25],rchild[N*25],root[N];
int a[N],b[N],cnt;
map<int,int>mp;
void build(int l,int r,int root){
if(l==r){
tree[root]=0;
return;
}
int mid=l+r>>1;
build(l,mid,lchild[root]=++cnt);
build(mid+1,r,rchild[root]=++cnt);
tree[root]=tree[lchild[root]]+tree[rchild[root]];
return ;
}
void update(int last,int cur,int l,int r,int x){
tree[cur]=tree[last];
lchild[cur]=lchild[last];
rchild[cur]=rchild[last];
if(l==r){
tree[cur]++;
return;
}
int mid=l+r>>1;
if(x<=mid) update(lchild[last],lchild[cur]=++cnt,l,mid,x);
else update(rchild[last],rchild[cur]=++cnt,mid+1,r,x);
tree[cur]=tree[lchild[cur]]+tree[rchild[cur]];
return ;
}
int query(int last,int cur,int l,int r,int k){
if(l==r){
//printf("l=%d r=%d k=%d\n",l,r,k);
return l;
}
int mid=l+r>>1;
int now=tree[lchild[cur]]-tree[lchild[last]];//注意判断的是左子树的size哦
// printf("left=%d mid=%d right=%d now=%d k=%d\n",l,mid,r,now,k);
if(now>=k) return query(lchild[last],lchild[cur],l,mid,k);
else return query(rchild[last],rchild[cur],mid+1,r,k-now);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
cnt=0;
mp.clear();//???
int n,m,ss=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
/* for(int i=1;i<=n;i++){
if(i!=n) printf("b[%d]=%d ",i,b[i]);
else printf("b[%d]=%d\n",i,b[i]);
}
*/
int t=unique(b+1,b+1+n)-b-1;//离散化
//printf("t=%d\n",t);
build(1,t,++cnt);
root[0]=1;
for(int i=1;i<=t;i++){
mp[b[i]]=i;
}
for(int i=1;i<=n;i++){
root[i]=++cnt;
update(root[i-1],root[i],1,t,mp[a[i]]);
}
while(m--){
int left,right,k;
scanf("%d%d%d",&left,&right,&k);
printf("%d\n",b[query(root[left-1],root[right],1,t,k)]);//query返回的是第k大的数离散化后的下标,所以b[query]才是原来的值
}
}
return 0;
}