题意

给定一个数列,给出若干个询问(l,r,k),求出[l,r]区间内第k小的数。

做法

用若干棵线段树分别维护前缀Si的离散化后的该数的个数,即在某棵线段树中,第i个位置表示离散化后大小为i的元素的个数,查询时在线段树上进行二分。

代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
class node{
public:
    int l,r, sum;
    node  *linkl, *linkr;
};
const int nn=100005;
node* root[nn];
class node1{
public:
    int x, num;
} a1[nn];
int a[nn];
int num;
int hash[nn];
int n,m;
void build(node *&p, int l, int r){
    p=(node*)malloc(sizeof(node));
    p->l = l; p->r = r; p->linkl = p->linkr = NULL;
    if (l < r){
        int mid = (l + r) >> 1;
        build(p->linkl, l, mid);
        build(p->linkr, mid+1, r);
        p->sum = p->linkl->sum + p->linkr->sum;
    } else{
        p->sum = 0;
    }
}
void build1(int x, node *&p, node *p1, int l,int r){
    p=(node*)malloc(sizeof(node));
 
    p->l = l; p->r = r;
    p->linkl = p->linkr = NULL;
    if (l < r) {
        int mid = (l + r) >> 1;
        if (x <= mid){
            build1(x, p->linkl, p1->linkl, l, mid);
            p->linkr = p1->linkr;
        } else {
            build1(x, p->linkr, p1->linkr, mid+1, r);
            p->linkl = p1->linkl;
        }
        p->sum = p->linkl->sum + p->linkr->sum;
    } else p->sum = p1->sum + 1;
}
inline int check(node *p1, node *p2, int k){
    while (p1->l != p1->r){
        if (k <= p2->linkl->sum - p1->linkl->sum) {
            p2 = p2 -> linkl; p1 = p1 -> linkl;
        } else{
            k -= (p2 -> linkl->sum - p1->linkl->sum);
            p2 = p2 -> linkr; p1 = p1 ->linkr;
        }
    }
    return (p1->l);
}
int scan(){
    char c;
    int x(0);
    bool f(false);
    while(c=getchar(),c==' ' || c== '\n');
    if (c == '-') {
        f = true;
        c = getchar();
    }
    x=c-'0';
    while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
    if (f) x = 0 - x;
    return x;
}
void qsort(int l, int r){
    node1 mid=a1[(l + r) >> 1];
    int i(l), j(r);
    node1 t;
    do{
        while (a1[i].x < mid.x) ++i;
        while (a1[j].x > mid.x) --j;
        if (i <= j){
            t = a1[i]; a1[i] = a1[j]; a1[j] = t;
            ++i; --j;
        }
    } while (i < j);
    if (l < j) qsort(l, j);
    if (i < r) qsort(i, r);
}
int main(){
    freopen("poj2104.in", "r", stdin);
    freopen("poj2104.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for (int i=1;i<=n;++i){
        a1[i].x = scan();
        a1[i].num = i;
    }
    qsort(1, n);
    a[a1[1].num] = 1;
    hash[1] = a1[1].x;
    num = 1;
    for (int i=2;i<=n;++i){
        if (a1[i].num != a1[i-1].num) ++num;
        a[a1[i].num] = num;
        hash[num] = a1[i].x;
    }
    build(root[0], 1, num);
    for (int i=1;i<=num;++i) build1(a[i], root[i], root[i-1], 1, num);
    int l,r,k;
    for (int i=1;i<=m;++i){
        l = scan(); r = scan(); k = scan();
        printf("%d\n", hash[check(root[l-1], root[r], k)]);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}