区间k大数(归并树)

给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。

Input
输入描述:

第一行包含一个数n,表示序列长度。

第二行包含n个正整数,表示给定的序列。

第三个包含一个正整数m,表示询问个数。

接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。

输入样例:

5

1 2 3 4 5

2

1 5 2

2 3 2

Output
输出描述:

总共输出m行,每行一个数,表示询问的答案。

输出样例:

4

2

#define _CRT_SBCURE_NO_DEPRECATE
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

#define maxn 100005
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;

vector<int> T[maxn << 2];
int N, Q;

void build(int l, int r, int rt) {
    if(l == r) {
        int val;
        scanf("%d", &val);
        // 从左到右的每个子节点
        T[rt].push_back(val);
        return;
    }

    int mid = (l + r) >> 1;

    build(lson);
    build(rson);

    T[rt].resize(r - l + 1); // 注意父节点的大小
    merge(T[rt<<1].begin(), T[rt<<1].end(), T[rt<<1|1].begin(), T[rt<<1|1].end(), T[rt].begin());
}

// 计算[L,R]中小于等于val的个数 
int query(int L, int R, int val, int l, int r, int rt) {
    if(L == l && R == r) {
        // 返回不超过val的个数 
        return upper_bound(T[rt].begin(), T[rt].end(), val) - T[rt].begin();
    }

    int mid = (l + r) >> 1;

    if(R <= mid) return query(L, R, val, lson);
    else if(L > mid) return query(L, R, val, rson);
    return query(L, mid, val, lson) + query(mid + 1, R, val, rson);
}

int main() {
    // 提升读写速度 
    ios::sync_with_stdio(false);
    cin.tie(0);

    int a, b, c, k, left, right, mid;
    scanf("%d", &N);
    build(1, N, 1);
    scanf("%d", &Q);
    while(Q--) {
        scanf("%d%d%d", &a, &b, &k);
        left = -1; right = N - 1;
        k = b - a + 2 - k; 
        while(right - left > 1) { // 在T[1]的 0 - N-1 中进行二分搜索 
            mid = (left + right) >> 1;
            // 第一个节点是都排序好的 
            // 返回c为[a,b]区间中小于等于T[1][mid]的个数
            c = query(a, b, T[1][mid], 1, N, 1);
            if(c >= k) right = mid;
            else left = mid;
        }
        printf("%d\n", T[1][right]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39778570/article/details/81873714