题解【bzoj1503 [NOI2004]郁闷的出纳员】
Description
给出一个下限 \(m\) ,要求维护以下操作
- 插入一个数(如果小于下限就不加)
- 给每个数加上一个数
- 给每个数减去一个数,并且删除掉 \(< m\) 的所有数
- 求目前第 \(k\) 大的数(注意是第 \(k\) 大!从大到小排序后第 \(k\) 个)
最后还要输出所有 3 操作一共删掉了多少个数
\(n \leq 10^5\)
Solution
fhqtreap大法吼!
由于修改操作是全体操作,可以用一个 \(delta\) 记录修改总量
对于 1 操作插入权值 \(x - delta\)(如果 x <= m 就算了
对于 2 操作直接把 \(delta += x\)
对于 3 操作,先把 \(delta -= x\) ,然后把小于 \(m - delta\) 的全部删掉
具体实现可以 split 出来两个子树,然后直接让 root = 右子树,最后要输出的 ans += 左子树的 siz
对于 4 操作,split一下就行了
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 100100;
int n, m, delta;
struct node {
int d, rnd, siz;
node *ch[2];
inline void upd() {
int ret = 1; if(ch[0]) ret += ch[0]->siz;
if(ch[1]) ret += ch[1]->siz; siz = ret;
}
}pool[N], *cur = pool, *root;
inline int siz(node *p) { return p ? p->siz : 0; }
inline node *New(int d) { node *p = (cur++); p->d = d, p->siz = 1, p->rnd = rand(); return p; }
inline node *merge(node *p, node *q) {
if(!p || !q) return p ? p : q;
if(p->rnd < q->rnd) { p->ch[1] = merge(p->ch[1], q); p->upd(); return p; }
if(p->rnd >= q->rnd) { q->ch[0] = merge(p, q->ch[0]); q->upd(); return q; }
return 0;
}
inline void split(node *r, int k, node *&p, node *&q) {
if(!r) { p = q = 0; return ; }
if(siz(r->ch[0]) >= k) q = r, split(r->ch[0], k, p, r->ch[0]);
else p = r, split(r->ch[1], k - siz(p->ch[0]) - 1, r->ch[1], q); r->upd();
}
inline int rk(node *r, int x) {
return !r ? 0 : (r->d >= x ? rk(r->ch[0], x) : (siz(r->ch[0]) + 1 + rk(r->ch[1], x)));
}
inline node *del(int x) {
int k = rk(root, x); node *p, *q;
split(root, k, p, q); root = q; return p;
}
int main() { int ans = 0;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
char op[5]; int d;
scanf("%s %d", op, &d);
if(op[0] == 'I') {
if(d < m) continue ;
if(!root) { root = New(d - delta); continue ; }
node *p, *q; split(root, rk(root, d - delta), p, q);
root = merge(merge(p, New(d - delta)), q);
} else if(op[0] == 'A') delta += d;
else if(op[0] == 'S') {
delta -= d; node *p = del(m - delta);
ans += siz(p);
} else {
// printf("%d\n", siz(root));
if(siz(root) < d) { printf("-1\n"); continue ; }
int sizz = siz(root);
node *p, *q, *r; split(root, (sizz - d + 1) - 1, p, q);
split(q, 1, q, r); printf("%d\n", q->d + delta); root = merge(merge(p, q), r);
}
} printf("%d\n", ans);
return 0;
}