ZOJ2112 Dynamic Rankings 线段树+平衡树

有修改的区间第K大数

惭愧啊,到现在才做到这道题,这道题公认有两种做法,一种是树状数组+主席树,遗憾地说我不会……

另外一种是线段树套平衡树,我用的是这种方法,只要线段树每一个节点都是一棵平衡树,我们就可以对序列进行动态修改了。

代码上,主代码部分和线段树部分我写的,treap参照了silver__bullet的代码,为防止内存开销过大,采用动态建树,恰好我不会指针……

//BZOJ上面A的……
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = ~0u >> 1;
const int N = (int)1e5 + 10;
const int maxn = (int)1e9 + 1;
#define lson l, m, n << 1
#define rson m + 1, r, n << 1 | 1
int x[N], n, m;
struct Treap{
    struct node{
        node *ch[2];
        int v, p, sz;
        node(int _v, node *n):
            v(_v){ch[0] = ch[1] = n; p = rand(); sz = 1;}
        void update(){sz = ch[0]->sz + ch[1]->sz + 1;}
    };
    node *root, *null;
    Treap(){
    }
    void init(){
        null = new node(0, 0); null->sz = 0; null->p = inf;
        null->ch[0] = null->ch[1] = null;
        root = null;
    }
    void rotate(node *&t, bool d){
        node *_t = t->ch[d];
        t->ch[d] = _t->ch[!d];
        _t->ch[!d] = t;
        _t->update();
        t->update();
        t = _t;
    }
    void __insert(node *&t, int val){
        if (t == null){
            t = new node(val, null);
            return;
        }
        bool d = val > t->v;
        __insert(t->ch[d], val);
        if (t->ch[d]->p < t->p) rotate(t, d);
        t->update();
    }
    void __del(node *&t, int val){
        if (t == null) return;
        if (val == t->v){
            bool d = t->ch[1]->p < t->ch[0]->p;
            if (t->ch[d] == null){
                delete t;
                t = null;
                return;
            }
            rotate(t, d);
            __del(t->ch[!d], val);
        }else{
            bool d = val > t->v;
            __del(t->ch[d], val);
        }
        t->update();
    }
    int __rank(node *t, int val){
        if (t == null) return 0;
        int num = t->ch[0]->sz;
        if (val < t->v) return __rank(t->ch[0], val);
        return num + 1 + __rank(t->ch[1], val);
    }
    void __show(node *x){
        if (x == null) return;
        __show(x->ch[0]);
        printf("%d ", x->v);
        __show(x->ch[1]);
    }
    void insert(int val){
        __insert(root, val);
    }
    void del(int val){
        __del(root, val);
    }
    int rank(int val){
        return __rank(root, val);
    }
    void show(){
        __show(root);
        puts("");
    }
    void __fre(node *t){
        if (t == null) return;
        __fre(t->ch[0]);
        __fre(t->ch[1]);
        delete t;
    }
    void fre(){
        __fre(root);
    }
};
struct segtree{
    Treap s[N << 2];
    void build(int l, int r, int n){
        s[n].init();
        for (int i = l; i <= r; i++)
            s[n].insert(x[i]);
        if (l == r) return;
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
    }
    void del(int l, int r, int n){
        s[n].fre();
        if (l == r) return;
        int m = (l + r) >> 1;
        del(lson);
        del(rson);
    }
    void update(int nn, int a, int l, int r, int n){
        s[n].del(x[nn]);
        s[n].insert(a);
        if (l == r) return;
        int m = (l + r) >> 1;
        if (nn <= m) update(nn, a, lson);
        else update(nn, a, rson);
    }
    int query(int ll, int rr, int val, int l, int r, int n){
        if (ll == l && rr == r){
            return s[n].rank(val);
        }
        int m = (l + r) >> 1;
        if (rr <= m) return query(ll, rr, val, lson);
        else if (ll > m) return query(ll, rr, val, rson);
        else return query(ll, m, val, lson) + query(m + 1, rr, val, rson);
    }
};
segtree T;
int check(int L, int R, int val, int k){
    int a = T.query(L, R, val - 1, 1, n, 1);
    int b = T.query(L, R, val, 1, n, 1);
    if (k > a && k <= b) return 1;
    if (k <= a) return 0;
    if (k > b) return -1;
}
int bs(int l, int r, int L, int R, int k){
    while(l <= r){
        int m = (l + r) >> 1;
        int res = check(L, R, m, k);
        if (res == 1) return m;
        else if (res == -1) l = m + 1;
        else r = m - 1;
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in", "rt", stdin);
    #endif
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
    T.build(1, n, 1);
    char op[5]; int l, r, k;
    while(m--){
        scanf("%s", op);
        if (op[0] == 'Q'){
            scanf("%d%d%d", &l, &r, &k);
            int ans = bs(0, maxn, l, r, k);
            printf("%d\n", ans);
        }else{
            scanf("%d%d", &l, &r);
            T.update(l, r, 1, n, 1);
            x[l] = r;
        }
    }
    T.del(1, n, 1);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值