#include<bits/stdc++.h>
#define reint register int
using namespace std;
int n,m;
inline void read(int &a) {
int x(0),y(1);
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-')y=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
a=x*y;
return;
}
inline void write(int x) {
if(x<0) {
putchar('-');
x=-x;
write(x);
} else {
if(x>9) {
write(x/10);
}
putchar(x%10+'0');
}
}
int s[200005],p,root[200005],top,s_[200005],q,k;
struct nod {
int l,r,val;
} tree[100000005];
int update(int node,int l,int r) {
int new_node=++top;
tree[new_node]=tree[node];
tree[new_node].val++;
if(l==r) {
return new_node;
} else {
int mid=(l+r)>>1;
if(p<=mid) {
tree[new_node].l=update(tree[new_node].l,l,mid);
} else {
tree[new_node].r=update(tree[new_node].r,mid+1,r);
}
}
return new_node;
}
void build(int &node,int l,int r) {
node=++top;
tree[node].val=0;
if(l==r) {
return;
}
int mid=(l+r)>>1;
build(tree[node].l,l,mid);
build(tree[node].r,mid+1,r);
}
int query(int lnode,int rnode,int l,int r,int k) {
if(l==r) {
return l;
} else {
int x=tree[tree[rnode].l].val-tree[tree[lnode].l].val;
int mid=(l+r)>>1;
if(k<=x)
return query(tree[lnode].l,tree[rnode].l,l,mid,k);
else
return query(tree[lnode].r,tree[rnode].r,mid+1,r,k-x);
}
}
int main() {
reint i,l,r;
scanf("%d",&n);
scanf("%d",&m);
for(i=1; i<=n; ++i) {
read(s[i]);
s_[i]=s[i];
}
sort(s_+1,s_+n+1);
q=unique(s_+1,s_+n+1)-s_-1;
build(root[0],1,q);
for(i=1; i<=n; ++i) {
p=lower_bound(s_+1,s_+1+q,s[i])-s_;
root[i]=update(root[i-1],1,q);
}
for(i=1; i<=m; ++i) {
read(l);read(r);read(k);
write(s_[query(root[l-1],root[r],1,q,k)]);
putchar('\n');
}
}
查询第k小的方法解释:
图
片
来
源
^{^{图片来源}}
图片来源
假设我们要查1 ~ 3中第2大的值,我们要先确定查找的范围,也就是从第零个根(红色)到第三个根(绿色)的第2大,然后从做左到右按顺序查,先找到3的左节点和一的左节点,看这两个节点之间有几个在1 ~ 3之间(也就是用左子节点的值减去右子节点的值(因为节点存的就是数的个数)),显然减完后只有1,也就是这个区间只有一个数,然而我们要找第二小,因此要找右子节点,又因为我们是按数的顺序建的树,所以在左子节点那里面的一个数一定小于右子节点的所有数,所以我们只需要在右子节点里面找到第2-1大的数,就是整个区间第2大的数,后面的按这个顺序推下去,找到根节点就返回下标,就完成了查询操作。
转载请注明出处,作者:Andysun06
|