poj2104 K-th Number (static interval k is large, chairman tree)

Chairman tree

Given a number sequence with n elements, each time you ask which is the smallest number c in the interval [a, b].

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define Rep(i, l, r) for (int i = l;i <= r;++i)
#define Rrep(i, r, l) for (int i = r;i >= l;--i)
const int maxn = 1e5 + 123;
struct Solution {
    /*主席树离线区间k大*/
    int ls[maxn*20], rs[maxn*20];//每个节点的左右孩子节点的编号
    int sum[maxn*20];
    int root[maxn];
    int tot;//节点数
    void init() {
        tot = 0;
    }
    //建立空树,定下线断树的形态
    void build(int &rt, int l, int r) {
        rt = ++tot;
        sum[rt] = 0;
        if (l == r) return ;
        int m = (l + r) >> 1;
        build(ls[rt], l, m);
        build(rs[rt], m + 1, r);
    }
    /*每次修改只需要新建log(n)个节点*/
    void updata(int last, int& rt, int l, int r, int p) {
        rt = ++tot;
        ls[rt] = ls[last];
        rs[rt] = rs[last];
        sum[rt] = sum[last] + 1;
        if (l == r) return ;
        int m = (l + r) >> 1;
        if (p <= m) updata(ls[last], ls[rt], l, m, p);
        else updata(rs[last], rs[rt], m + 1, r, p);
    }
    /*两颗树同时向下找,为了是相减求出区间的数出现次数的情况*/
    int find(int ss, int tt,int l, int r, int k) {
        if (l == r) return l;/*k大的值,不过是离散化后的,最后还要通过hash函数求出原来的值*/
        int m = (l + r) >> 1;
        int cnt = sum[ls[tt]] - sum[ls[ss]];
        if (k <= cnt) return find(ls[ss], ls[tt], l, m, k);
        return find(rs[ss], rs[tt], m + 1, r, k - cnt);/*important*/
    }

}solve;
int num[maxn];
int Hash[maxn];

int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // ios::sync_with_stdio(false);
    // cout.sync_with_stdio(false);
    // cin.sync_with_stdio(false);
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        solve.init();
        Rep(i, 1, n) {
            scanf("%d", &num[i]);
            Hash[i] = num[i];
        }
        /*离散化, 处理出所有可能出现的数字*/
        sort(Hash + 1, Hash + 1 + n);
        int cnt = unique(Hash + 1, Hash + 1 + n) - Hash - 1;
        Rep(i, 1, n) {
            num[i] = lower_bound(Hash + 1, Hash + 1 + cnt, num[i]) - Hash;
        }
        /*建立空树,确定线断树形态*/
        solve.build(solve.root[0], 1, cnt);
        Rep(i, 1, n) {
            solve.updata(solve.root[i - 1], solve.root[i], 1, cnt, num[i]);
        }
        Rep(i, 1, m) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            int p = solve.find(solve.root[a - 1], solve.root[b], 1, cnt, c);
            printf("%d\n", Hash[p]);
        }
    }

    // showtime;
    return 0;
}

Guess you like

Origin blog.csdn.net/KIJamesQi/article/details/52262417