题解【bzoj1503 [NOI2004]郁闷的出纳员】

Description

给出一个下限 \(m\) ,要求维护以下操作

  1. 插入一个数(如果小于下限就不加)
  2. 给每个数加上一个数
  3. 给每个数减去一个数,并且删除掉 \(< m\) 的所有数
  4. 求目前第 \(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; 
}
posted @ 2018-12-29 22:24  AcFunction  阅读(221)  评论(0编辑  收藏  举报