[poj 2104 K-th Number] 主席树 区间第K大

[poj 2104 K-th Number] 主席树 区间第K大

题目链接[poj 2104 K-th Number]
题意描述:给定 N 个数a1,a2,,an M 次查询,每次查询区间第L个数到第 R 个数中的第K大数。
相似题目[hdu 4417 Super Mario] 主席树+离散化
解题思路:首先对数据离散化。然后线段树记录区间中的数字出现的次数。主席树保存 N 棵线段树,每棵线段树都保存着前N个数字的信息。查询区间 [L,R] 的第 K 大, 只要根据第L1棵数和第 R <script type="math/tex" id="MathJax-Element-935">R</script>棵树二分向叶子节点就好了。

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second
#define __mid__         int mid = ((l + r) >> 1)

typedef __int64 LL;
typedef unsigned __int64 ULL;
typedef pair<int, int> PII;

const int MAXN = 100000 + 5;
const int MAXM = 5000 + 5;
const int INF = 0x3f3f3f3f;

int N, M, A[MAXN], F[MAXN], L, R, K;
int root[MAXN], FSZ, TSZ;

struct TNode {
    int ls, rs, sum;
} node[MAXN * 20];
void hash_init() {
    sort(F, F + N);
    FSZ = unique(F, F + N) - F;
    F[FSZ ++] = INF;
}
int getID(const int& x) { return lower_bound(F, F + FSZ, x) - F + 1;}
int build(int l, int r) {
    int rt = TSZ ++;
    node[rt].sum = 0;
    if(l == r) { node[rt].ls = node[rt].rs = -1; return rt;}
    __mid__;
    node[rt].ls = build(l, mid);
    node[rt].rs = build(mid + 1, r);
    return rt;
}
int update(const int& pos, int r1, int l, int r) {
    int r2 = TSZ ++;
    node[r2] = node[r1];
    node[r2].sum ++;
    if(l == r) return r2;
    __mid__;
    if(pos <= mid) node[r2].ls = update(pos, node[r1].ls, l, mid);
    else node[r2].rs = update(pos, node[r1].rs, mid + 1, r);
    return r2;
}
int query(int k, int r1, int r2, int l, int r) {
    if(l == r) return l;
    __mid__;
    int x = node[node[r2].ls].sum - node[node[r1].ls].sum;
    if(k <= x) return query(k, node[r1].ls, node[r2].ls, l, mid);
    else return query(k - x, node[r1].rs, node[r2].rs, mid + 1, r);
}
int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif // ONLINE_JUDGE
    while(~scanf("%d %d", &N, &M)) {
        for(int i = 0; i < N; i++) scanf("%d", &A[i]), F[i] = A[i];
        hash_init();
        TSZ = 0;
        root[0] = build(1, FSZ);
        for(int i = 0; i < N; i++) {
            root[i + 1] = update(getID(A[i]), root[i], 1, FSZ);
        }
        while(M --) {
            scanf("%d %d %d", &L, &R, &K);
            int ret = query(K, root[L - 1], root[R], 1, FSZ) - 1;
            printf("%d\n", F[ret]);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值