主席树初步 HDU2665的区间第k小

首先看一下这个人的blog吧,讲的精炼 http://blog.sina.com.cn/s/blog_4a0c4e5d0101c8fr.html

然后再推荐一下这个人的blog:http://www.cnblogs.com/zinthos/p/3899565.html

这两个博客看了就差不多了。

自己说一下对代码的理解吧。

就是每一个数字开一个空间,然后每个空间用tot标号,最后tot就是总体开的数目。然后不同的线段树可能有相同的左儿子或者右二子(或者左=右,右=左),然后具体都是通过tot的储存值表现出来,大致就是这样吧。

代码挺裸的:

//看看会不会爆int! 或者绝对值问题。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define ALL(a) a.begin(), a.end()
const int maxn = 100000 + 5;
struct Segment{
    int lb, rb;
    int cnt;
    Segment(int l = 0, int r = 0, int c = 0): lb(l), rb(r), cnt(c){}
}s[maxn * 20];
int root[maxn];
int a[maxn];
int n, m, tot;

int buildtree(int l, int r){
    int k = tot++;
    if (l == r){
        s[k] = Segment(0, 0, 0);
        return k;
    }
    int mid = (l + r) / 2;
    if (mid >= l) s[k].lb = buildtree(l, mid);
    else s[k].rb = buildtree(mid + 1, r);
    return k;
}

inline void push_up(int o){
    s[o].cnt = s[s[o].lb].cnt + s[s[o].rb].cnt;
}

int update(int o, int l, int r, int pos, int val){
    int k = tot++;
    s[k] = s[o];
    if (l == r && l == pos){
        s[k].cnt += val;
        return k;
    }
    int mid = (l + r) / 2;
    if (mid >= pos) s[k].lb = update(s[o].lb, l, mid, pos, val);
    else s[k].rb = update(s[o].rb, mid + 1, r, pos, val);
    push_up(k);
    return k;
}

int query(int o1, int o2, int l, int r, int num){
    if (l == r) return l;
    int mid = (l + r) / 2;
    int res = s[s[o1].lb].cnt - s[s[o2].lb].cnt;
    if (res >= num) return query(s[o1].lb, s[o2].lb, l, mid, num);
    else return query(s[o1].rb, s[o2].rb, mid + 1, r, num - res);
}

int main(){
    while (scanf("%d%d", &n, &m) == 2){
        vector<int> v(n);
        for (int i = 1; i <= n; i++){
            scanf("%d", a + i);
            v[i - 1] = a[i];
        }
        sort(ALL(v));
        v.erase(unique(ALL(v)), v.end());
        for (int i = 1; i <= n; i++){
            a[i] = lower_bound(ALL(v), a[i]) - v.begin() + 1;
        }
        tot = 0; int len = v.size();
        root[0] = buildtree(1, len);
        for (int i = 1; i <= n; i++){
            root[i] = update(root[i - 1], 1, len, a[i], 1);
        }
        for (int i = 1; i <= m; i++){
            int l, r, num;
            scanf("%d%d%d", &l, &r, &num);
            int pos = query(root[r], root[l - 1], 1, len, num);
            printf("%d
", v[pos - 1]);
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/heimao5027/p/5853159.html