第k小的数

第k小的数

题目描述

你为SKZ公司的数据结构部门工作,你的工作是重新写一个程序,这个程序能快速地找到一段数列中第k小的数。
就是说,给定一个整数数列a[1..n],其中每个元素都不相同,你的程序要能回答一组格式为Q (i , j , k)的查询,Q(i, j ,k)的意思是“在a[i..j]中第k小的数是多少?”
例如令 a = {1, 5, 2, 6, 3, 7, 4},查询格式为Q (2 , 5 , 3),数列段a[2..5] = {5, 2, 6, 3},第3小的数是5,所以答案是5。

输入

第一行包括一个正整数n,代表数列的总长度,还有一个数m,代表有m个查询。n、m满足:1≤n≤100 000,1≤m≤5 000。
第二行有n个数,代表数列的元素,所有数都不相同,而且不会超过109
接下来有m行,每行三个整数i、j、k,代表一次查询,i、j、k满足:1≤i≤j≤n, 1≤k≤j−i+1。

输出

每行一个输出每个查询的答案

样例输入

7 3 
1 5 2 6 3 7 4 
2 5 3 
4 4 1 
1 7 3

样例输出

5
6
3


主席树裸题,就是这样


#include<cmath> 
#include<cstdio> 
#include<cstring> 
#include<iostream> 
#include<algorithm> 
using namespace std; 
#define N 150010 
int lim=1000000000; 
int cnt,n,m; 
int root[N],w[N*31]; 
int ch[N*31][2]; 
void addnew(int x,int &y,int l,int r,int v) 
{ 
    y=++cnt; 
    w[y]=w[x]+1; 
    if(l==r) return; 
    ch[y][0]=ch[x][0],ch[y][1]=ch[x][1]; 
    int mid=(l+r)>>1; 
    if(v<=mid) addnew(ch[x][0],ch[y][0],l,mid,v); 
    else addnew(ch[x][1],ch[y][1],mid+1,r,v); 
} 
int check(int L,int R,int k) 
{ 
    int x=root[L-1],y=root[R]; 
    int l=-lim,r=lim; 
    while(l<r) 
    { 
        int mid=(l+r)>>1; 
        if(w[ch[y][0]]-w[ch[x][0]]<k) 
        { 
            l=mid+1; 
            k-=w[ch[y][0]]-w[ch[x][0]]; 
            y=ch[y][1],x=ch[x][1]; 
        } 
        else r=mid,x=ch[x][0],y=ch[y][0]; 
    } 
    return l; 
} 
int main() 
{ 
    scanf("%d%d",&n,&m); 
    int aa,bb,cc; 
    for(int i=1;i<=n;i++) 
    { 
        scanf("%d",&aa); 
        addnew(root[i-1],root[i],-lim,lim,aa); 
    } 
    for(int i=1;i<=m;i++) 
    { 
        scanf("%d%d%d",&aa,&bb,&cc); 
        printf("%d\n",check(aa,bb,cc)); 
    } 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值