CWOJ 1198 主席树之区间第k大

https://cwoj.tk/problempage.php?problem_id=1198

出这道题的目的是学习最基础主席树,对已掌握主席树的选手,完全不需要去看,对完全不会主席树的同学,有学习的价值

稍后可能附上具体思路

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
using namespace std;

const int N = 100010;
int n, m, a[N], tem[N], ntem;

const int M = N * (4 + 17);
int nnod, lid[M], rid[M], Tid[N], val[M];

//build an empty complete tree, of vital importance!
int plant(int l, int r){
    int t = ++nnod;
    val[t] = 0;
    if(l == r) return t;
    int mid = (l + r) >> 1;
    lid[t] = plant(l, mid);
    rid[t] = plant(mid + 1, r);
    return t;
}

//build this tree from father tree
int update(int id, int l, int r, int p, int v){
    int t = ++nnod;
    lid[t] = lid[id], rid[t] = rid[id];
    val[t] = val[id] + v;
    if(l == r) return t;
    int mid = (l + r) >> 1;
    if(p <= mid) lid[t] = update(lid[t], l, mid, p, v);
    else rid[t] = update(rid[t], mid + 1, r, p, v);
    return t;
}

//query k-th element in segment a[l, r]
int queryKth(int Lid, int Rid, int l, int r, int k){
    if(l == r) return tem[l];
    int mid = (l + r) >> 1;
    int lval = val[lid[Rid]] - val[lid[Lid]];//very seay to get wrong!
    if(lval >= k) return queryKth(lid[Lid], lid[Rid], l, mid, k);
    else return queryKth(rid[Lid], rid[Rid], mid + 1, r, k - lval);
}

int main(){
    while(scanf("%d", &n) != EOF){
        //read array a
        ntem = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d", a + i);
            tem[++ntem] = a[i];
        }

        //hash: in Chinese "Li San Hua"
        sort(tem + 1, tem + 1 + ntem);
        ntem = (int)(unique(tem + 1, tem + 1 + ntem) - (tem + 1));

        //build an empty complete tree
        nnod = 0;
        Tid[0] = plant(1, ntem);

        //build another n trees
        for(int i = 1; i <= n; i++){
            int p = (int)(lower_bound(tem + 1, tem + 1 + ntem, a[i]) - tem);
            Tid[i] = update(Tid[i-1], 1, ntem, p, +1);
        }

        //get answers
        scanf("%d", &m);
        for(int i = 1; i <= m; i++){
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            int ans = queryKth(Tid[l-1], Tid[r], 1, ntem, k);
            printf("%d\n", ans);
        }
    }
    return 0;
}

你可能感兴趣的:(CWOJ 1198 主席树之区间第k大)