【NOI2004】郁闷的出纳员
https://daniu.luogu.org/problem/show?pid=1486
由于每次调工资都是对全体员工,所以可以用一个标记来记录全体员工的工资偏移值。
每次下调工资都有可能造成有员工的工资低于下界,这时需要将他们一起移除。可以用Splay来维护员工工资的集合。
#include <iostream> using namespace std; namespace splay { enum direction { l = 0, r = 1 }; const int inf = 0x7fffffff; struct node *nil = 0; struct node { int val, cnt, size; node *ch[2]; node(int v) : val(v), cnt(1), size(1) { ch[l] = ch[r] = nil; } int cmp(int v) { if (v == val || this == nil) return -1; else return (v < val) ? l : r; } int cmpkth(int k) { if (k <= ch[l]->size) return l; else if (k <= ch[l]->size + cnt) return -1; else return r; } void pullup() { size = cnt + ch[l]->size + ch[r]->size; } } * root; void init() { if (!nil) nil = new node(0); nil->cnt = nil->size = 0; nil->ch[l] = nil->ch[r] = nil; root = nil; } void rotate(node *&t, int d) { node *k = t->ch[d ^ 1]; t->ch[d ^ 1] = k->ch[d]; k->ch[d] = t; t->pullup(); k->pullup(); t = k; } void splay(node *&t, int v) { int d = t->cmp(v); if (d != -1 && t->ch[d] != nil) { int d2 = t->ch[d]->cmp(v); if (d2 != -1 && t->ch[d]->ch[d2] != nil) { splay(t->ch[d]->ch[d2], v); if (d == d2) { rotate(t, d2 ^ 1); rotate(t, d ^ 1); } else { rotate(t->ch[d], d2 ^ 1); rotate(t, d ^ 1); } } else rotate(t, d ^ 1); } } void splaykth(node *&t, int k) { int d = t->cmpkth(k); if (d == r) k -= t->ch[l]->size + t->cnt; if (d != -1) { int d2 = t->ch[d]->cmpkth(k); int k2 = (d2 == r) ? (k - t->ch[d]->ch[l]->size - t->ch[d]->cnt) : k; if (d2 != -1) { splaykth(t->ch[d]->ch[d2], k2); if (d == d2) { rotate(t, d2 ^ 1); rotate(t, d ^ 1); } else { rotate(t->ch[d], d2 ^ 1); rotate(t, d ^ 1); } } else rotate(t, d ^ 1); } } node *split(node *&t, int v) //t为大于等于v的树,返回严格小于v的树 { splay(t, v); node *t1, *t2; if (t->val >= v) { t1 = t; t2 = t->ch[l]; t->ch[l] = nil; } else { t1 = t->ch[r]; t2 = t; t->ch[r] = nil; } t->pullup(); t = t1; return t2; } node *join(node *t, node *t2) { if (t == nil) swap(t, t2); splay(t, inf); t->ch[r] = t2; t->pullup(); return t; } void insert(node *&t, int v) { node *k = split(t, v); if (t != nil && v == t->val) { t->cnt++; t->size++; } else k = join(k, new node(v)); t = join(k, t); } void remove(node *&t) { if (t != nil) { remove(t->ch[l]); remove(t->ch[r]); delete t; t = nil; } } } int n, minn, inc = 0, cnt = 0; int main() { using namespace splay; ios::sync_with_stdio(false); init(); cin >> n >> minn; char c; int k; node *nd; while (n--) { cin >> c >> k; switch (c) { case 'I': if (k >= minn) insert(root, k - inc); break; case 'A': inc += k; break; case 'S': inc -= k; nd = split(root, minn - inc); cnt += nd->size; remove(nd); break; case 'F': if (root->size < k) cout << -1 << endl; else { splaykth(root, root->size - k + 1); cout << root->val + inc << endl; } break; } } cout << cnt << endl; return 0; }