[NOI2004] 郁闷的出纳员 ——Treap+整体偏移量

题面

郁闷的出纳员

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

这里一个小技巧,题目让我们给所有员工加减 k k k的工资,我们不需要真的去树里面加;

我们只需要维护一个偏移量,对这个偏移量进行加减即可;


接着考虑删除会导致什么情况;

删除可能会导致员工离职,我们只需要像链表一样去操作即可;

不断的迭代去删除;

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 3e5 + 10,INF = 2e9+7;

struct Node{
    int lc,rc;
    int key,val;
    int cnt,size;
}tr[N];

int idx,root;

int new_node(int key){
    int p = ++idx;
    tr[p].key = key;
    tr[p].val = rand();
    tr[p].cnt = tr[p].size = 1;
    return p;
}
void push_up(int p){
    tr[p].size = tr[p].cnt + tr[tr[p].lc].size + tr[tr[p].rc].size;
}
void Rrotate(int &p){
    int q = tr[p].lc;
    tr[p].lc = tr[q].rc;
    tr[q].rc = p;
    p = q;
    push_up(tr[p].rc);
    push_up(p);
}
void Lrotate(int &p){
    int q = tr[p].rc;
    tr[p].rc = tr[q].lc;
    tr[q].lc = p;
    p = q;
    push_up(tr[p].lc);
    push_up(p);
}
void build(){
    root = new_node(-INF);
    tr[root].rc = new_node(INF);
    push_up(root);
    if(tr[tr[root].rc].val > tr[root].val){
        Lrotate(root);
    }
}
void insert(int &p,int key){
    if(!p){
        p = new_node(key);
        return;
    }
    if(tr[p].key == key){
        ++tr[p].cnt;
    }else if(tr[p].key > key){
        insert(tr[p].lc,key);
        if(tr[tr[p].lc].val > tr[p].val){
            Rrotate(p);
        }
    }else{
        insert(tr[p].rc,key);
        if(tr[tr[p].rc].val > tr[p].val){
            Lrotate(p);
        }
    }
    push_up(p);
}
void erase(int &p,int key){
    if(!p) return;
    if(tr[p].key == key){
        if(tr[p].cnt > 1){
             --tr[p].cnt;
        }
        else if(tr[p].lc || tr[p].rc){
            if(!tr[p].rc || tr[tr[p].lc].val > tr[tr[p].rc].val){
                //右旋 增加要删除结点的深度
                Rrotate(p);
                erase(tr[p].rc,key);
            }else{
                Lrotate(p);
                erase(tr[p].lc,key);
            }
        }else p = 0;//如果是叶子
    }else if(tr[p].key > key){
        erase(tr[p].lc,key);
    }else{
        erase(tr[p].rc,key);
    }
    push_up(p);
}
//根据rank查key->第k大
int query_key_by_rank(int p,int rank){
    if(!p) return INF;
    if(tr[tr[p].rc].size >= rank){
        return query_key_by_rank(tr[p].rc,rank);
    }
    else if(tr[tr[p].rc].size + tr[p].cnt >= rank){
        return tr[p].key;
    }
    else return query_key_by_rank(tr[p].lc,rank-tr[tr[p].rc].size-tr[p].cnt);
}
//查询小于key最大的数
int get_prev(int p,int key){
    if(!p) return -INF;
    if(tr[p].key >= key){
        return get_prev(tr[p].lc,key);
    }
    return max(tr[p].key,get_prev(tr[p].rc,key));
}
void solve(){
    int n,minn,offset = 0,leave = 0,now = 0;
    cin >> n >> minn;
    char opt;
    int k;
    build();
    for(int i=1;i<=n;++i){
        cin >> opt >> k;
        if(opt == 'I'){
            if(minn > k){
                continue;
            }
            else{
                insert(root,k - offset);
                ++now;
            }
        }
        else if(opt == 'A'){
            offset += k;
        }
        else if(opt == 'S'){
            offset -= k;
            //找所有满足小于minn - offset的值
            int tar = minn - offset,key;
            while((key = get_prev(root,tar))!=-INF){
                erase(root,key);
                ++leave;
                --now;
            }
        }
        else{
            if(now >= k) cout << offset+query_key_by_rank(root,k+1) << '\n';
            else cout << -1 << '\n';
        }
    }
    cout << leave << '\n';
}

int main(){
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值