【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;
}

 

posted @ 2017-09-16 18:41  ssttkkl  阅读(162)  评论(0编辑  收藏  举报