bzoj1503 [NOI2004]郁闷的出纳员

1503: [NOI2004]郁闷的出纳员

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 12785  Solved: 4577
[Submit][Status][Discuss]

Description

OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

Input

Output

输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。输出文件的最后一行包含一个整数,为离开公司的员工的总数。

Sample Input

9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

Sample Output

10
20
-1
2

HINT

I命令的条数不超过100000 A命令和S命令的总条数不超过100 F命令的条数不超过100000 每次工资调整的调整量不超过1000 新员工的工资不超过100000

分析:郁闷的程序员......这种样子的题一看就是要用数据结构来实现.考虑用splay来实现.对于I操作,直接插入就可以了.A,S两种操作是区间修改.因为是对整体修改,所以可以用一个变量sum表示当前的工资下界与最开始的工资下界相差多少.这样如果要插入一个数x,插入x-sum就可以了,最后+sum就能够还原了.每次S操作后要删除低于工资下界的人,维护一个特征点min - sum,为了方便处理,将这个点插入到splay中,转到根部,那么它的左子树连同它自己都要被删掉.保留右子树.

          需要注意的是可能会有多个数相同,那么删除就不能直接删掉整个点了,而要判断当前点的个数是否 > 1.第k大是从大到小第k个,而不是从小到大.还要及时更新size数组.一旦一个点的cnt或者size变了,就要更新它的父节点,连同自己.

          以前用的模板在这道题上有问题,换了一个更好的模板:

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

using namespace std;

const int maxn = 200010;

int n,minn,root,tot,sizee[maxn],ans,sum;
bool flag = false;

struct node
{
    int left,right,fa,v,cnt;
}e[maxn];

void update(int x)
{
    sizee[x] = e[x].cnt;
    if (e[x].left != 0)
        sizee[x] += sizee[e[x].left];
    if (e[x].right != 0)
        sizee[x] += sizee[e[x].right];
}

int getsize(int x)
{
    if (x == 0)
        return 0;
    return sizee[x];
}

void turnr(int x)
{
    int y = e[x].fa;
    int z = e[y].fa;
    e[y].left = e[x].right;
    if (e[x].right != 0)
        e[e[x].right].fa = y;
    e[x].fa = z;
    if (z != 0)
    {
        if (e[z].left == y)
            e[z].left = x;
        else
            e[z].right = x;
    }
    e[x].right = y;
    e[y].fa = x;
    update(x);
    update(y);
}

void turnl(int x)
{
    int y = e[x].fa;
    int z = e[y].fa;
    e[y].right = e[x].left;
    if (e[x].left != 0)
        e[e[x].left].fa = y;
    e[x].fa = z;
    if (z != 0)
    {
        if (e[z].left == y)
            e[z].left = x;
        else
            e[z].right = x;
    }
    e[x].left = y;
    e[y].fa = x;
    update(x);
    update(y);
}

void splay(int x)
{
    while (e[x].fa != 0)
    {
        int y = e[x].fa;
        int z = e[y].fa;
        if (z == 0)
        {
            if (x == e[y].left)
                turnr(x);
            else
                turnl(x);
        }
        else
        {
            if (e[z].left == y && e[y].left == x)
            {
                turnr(y);
                turnr(x);
            }
            else
            {
                if (e[z].right == y && e[y].right == x)
                {
                    turnl(y);
                    turnl(x);
                }
                else
                {
                    if (e[z].left == y && e[y].right == x)
                    {
                        turnl(x);
                        turnr(x);
                    }
                    else
                    {
                            turnr(x);
                            turnl(x);
                    }
                }
            }
        }
    }
    root = x;
}

void insert(int x)
{
    if (!root)
    {
        ++tot;
        e[tot].left = e[tot].right = e[tot].fa = 0;
        e[tot].v = x;
        e[tot].cnt = sizee[tot] = 1;
        root = tot;
        return;
    }
    int now = root,fa = 0;
    while (1)
    {
        if(e[now].v == x)
        {
            e[now].cnt++;
            update(now);
            update(fa);
            splay(now);
            break;
        }
        fa = now;
        if (e[now].v < x)
            now = e[now].right;
        else
            now = e[now].left;
        if (!now)
        {
            ++tot;
            e[tot].left = e[tot].right = 0;
            e[tot].fa = fa;
            e[tot].v = x;
            e[tot].cnt = sizee[tot] = 1;
            if (e[fa].v < x)
                e[fa].right = tot;
            else
                e[fa].left = tot;
            update(fa);
            splay(tot);
            break;
        }
    }
}

void clear(int x)
{
    e[x].fa = e[x].left = e[x].right = e[x].v = e[x].cnt = sizee[x] = 0;
}

void del()
{
    ans += sizee[e[root].left];
    e[root].left = 0;
    if (e[root].cnt > 1)
    {
        e[root].cnt--;
        update(root);
        return;
    }
    if (!e[root].right)
    {
        root = 0;
        return;
    }
    root = e[root].right;
    e[root].fa = 0;
}

int query(int x)
{
    int p = root;
    while (p != 0)
    {
        if (e[p].right != 0 && x <= sizee[e[p].right])
            p = e[p].right;
        else
        {
            int temp = getsize(e[p].right) + e[p].cnt;
            if (x <= temp)
            return e[p].v;
            x -= temp;
            p = e[p].left;
        }
    }
    return e[p].v;
}


int main()
{
    scanf("%d%d",&n,&minn);
    for (int i = 1; i <= n; i++)
    {
        char op[2];
        int k;
        scanf("%s",op);
        scanf("%d",&k);
        if (op[0] == 'I')
        {
            if (k < minn)
                continue;
            insert(k - sum);
        }
        if (op[0] == 'A')
            sum += k;
        if (op[0] == 'S')
        {
            sum -= k;
            insert(minn - sum);
            del();
        }
        if (op[0] == 'F')
        {
            update(root);
            if (sizee[root] < k)
                puts("-1");
            else
                printf("%d
",query(k) + sum);
        }
    }
    printf("%d
",ans);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/8261757.html