BZOJ 1503 [NOI2004]郁闷的出纳员 (Splaytree)

用Splaytree实现插入,删除一个区间,求小于某值的个数。

题意有个坑。。初始工资小于工资下届不计入离开公司的总数。。


#include 
   
   
    
    

const int maxn = 100000+10;
const int INF = 1<<30;

#define lson x->ch[0]
#define rson x->ch[1]
#define ket (root->ch[1]->ch[0])

struct NODE {
    NODE *pre, *ch[2];
    int val, id, sz, mark;

    void down() {
        if(mark) {
            if(ch[0]->pre) {
                ch[0]->mark += mark;
                ch[0]->val += mark;
            }
            if(ch[1]->pre) {
                ch[1]->mark += mark;
                ch[1]->val += mark;
            }
            mark = 0;
        }
    }

    void up() {
        sz = ch[0]->sz + ch[1]->sz + 1;
    }
}node[maxn], *null = &node[0], *root;

struct Splaytree {
    int top;

    void Rotate(NODE *x, int c) {
        NODE *y = x->pre;
        y->down(); x->down();
        y->ch[!c] = x->ch[c];
        if(x->ch[c] != null) x->ch[c]->pre = y;
        x->pre = y->pre;
        if(y->pre != null) y->pre->ch[ y->pre->ch[1]==y ] = x;
        x->ch[c] = y; y->pre = x;
        y->up();
    }

    void Splay(NODE *x, NODE *go) {
        while(x->pre != go) {
            if(x->pre->pre == go)   Rotate(x, x->pre->ch[0] == x);
            else {
                NODE *y = x->pre, *z = y->pre;
                int f = z->ch[1] == y;
                if(y->ch[f] == x)   Rotate(y, !f);
                else    Rotate(x, f);
                Rotate(x, !f);
            }
        }
        x->up();
        if(go == null)  root = x;
    }

    void RTO(int k, NODE *go) {
        NODE *x = root;
        x->down();
        while(lson->sz != k) {
            if(lson->sz > k)    x = lson;
            else {
                k -= lson->sz + 1;
                x = rson;
            }
            x->down();
        }
        Splay(x, go);
    }

    void debug(NODE *x) {
        if(x != null) {
            printf("节点: %2d  左儿子: %2d 右儿子: %2d size = %2d val = %2d\n",
                x->id, x->ch[0]->id, x->ch[1]->id, x->sz, x->val);
            x->down();
            debug(x->ch[0]);
            debug(x->ch[1]);
        }
    }

    NODE *newnode(int c, NODE* f=null) {
        NODE *x = &node[++top];
        x->id = top;
        x->val = c; x->sz = 1;
        x->mark = 0; x->pre = f;
        lson = rson = null;
        return x;
    }

    void init() {
        null->id = null->sz = null->val = null->mark = 0;
        top = 0;
        root = newnode(-INF);
        root->ch[1] = newnode(INF, root);
        root->ch[1]->up(); root->up();
    }

    void Insert(int c) {
        NODE *x = root;
        while(x->ch[ x->val <= c] != null) {
            x->down();
            x = x->ch[ x->val <= c];
        }
        x->down();
        x->ch[ x->val <= c] = newnode(c, x);
        Splay(x->ch[x->val<=c], null);
    }

    int find_cnt(NODE *x, int c) {
        if(x == null)   return 0;
        x->down();
        if(x->val < c) return lson->sz + 1 + find_cnt(rson, c);
        else    return find_cnt(lson, c);
    }

    void solve() {
        init();
        int n, m, k;
        scanf("%d%d", &n, &m);
        int ans = 0;
        while(n--) {
            char op[2];
            scanf("%s%d", op, &k);
            if(op[0] == 'I') {
                if(k >= m) Insert(k);
            }
            else if(op[0] == 'A') {
                root->mark += k; root->val += k;
            }
            else if(op[0] == 'S') {
                root->mark -= k; root->val -= k;
                int cnt = find_cnt(root, m);
                if(cnt >= 2) {
                    ans += cnt-1;
                    RTO(0, null);
                    RTO(cnt, root);
                    ket = null;
                    root->ch[1]->up(); root->up();
                }
            }
            else {
                if(root->sz-2 < k)  puts("-1");
                else {
                    RTO(root->sz-2-k + 1, null);
                    printf("%d\n", root->val);
                }
            }
        }
        printf("%d\n", ans);
    }
}spt;

int main(){
    spt.solve();
    return 0;
}

   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值