离散化:
对数组排完序后用unique去重,unique返回的是去重后的数组的末地址,减去第一个元素的地址就能得到去重后的数组大小,用lower_bound查找原数字在排序去重后的序列中的位序,用位序代替数字完成离散化。
#include
#include
using namespace std;
#define lson l,m,ls[rt]
#define rson m+1,r,rs[rt]
typedef long long ll;
const int maxn = 1e5 + 5;
int ls[maxn*30],rs[maxn*30],tot,rts[maxn];//tot为总结点数
int t[maxn*30];
int a[maxn],num[maxn];
void build(int l,int r,int &rt)
{
rt = ++tot;
t[rt] = 0;//建一棵全为0的空树。
if(l==r)
return ;
int m = l+r>>1;
build(lson);
build(rson);
}
void add(int p,int C,int l,int r,int &rt,int lst)
{
rt = ++tot;
ls[rt] = ls[lst],rs[rt] = rs[lst];
t[rt] = t[lst] + C; //先从上一个版本的结点拷贝信息,因为传的是引用,
if(l==r) //进入下一层递归时rt = ++tot;这一句会给新的结点编号。
return ;
int m = l+r>>1;
if(p<=m)
add(p,C,lson,ls[rt]);
else
add(p,C,rson,rs[rt]);
}
int query(int x,int y,int l,int r,int k)
{
if(l==r)
return l;
int c = t[ls[y]] - t[ls[x]];//c表示左子树中数字的数量
int m = l+r>>1;
if(c>=k)//k<=c时,第k小是左子树中的第k小。
return query(ls[x],ls[y],l,m,k);
else//k>c时,第k小是右子树中的第k-c小
return query(rs[x],rs[y],m+1,r,k-c);
}
int N,M,c,x,y,k;
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
tot = 0;
for(int i=1;i<=N;++i)
{
scanf("%d",&a[i]);
num[i] = a[i];
}
sort(num+1,num+N+1);
int cnt = unique(num+1,num+N+1)-(num+1);
build(1,cnt,rts[0]);
for(int i=1;i<=N;++i)
a[i] = lower_bound(num+1,num+cnt+1,a[i])-num;
for(int i=1;i<=N;++i)
add(a[i],1,1,cnt,rts[i],rts[i-1]);
while(M--)
{
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",num[query(rts[x-1],rts[y],1,cnt,k)]);
}
}
return 0;
}