【BZOJ1503】【NOI2004】郁闷的出纳员

【问题描述】

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

输入:

【分析】

    平衡树。我写splay。

    工资的加减,由于是对于所有员工的,所以不用修改每个员工的值,只要把总共的变化值delt记下来就行了。加入员工的时候,把初始工资减去delt。查询时第k多的工资,把工资下界减去delt。

    查询第k多的工资,也很简单。只要在平衡树每个节点多记一个参数,表示以它为根的子树的节点数。把第k多转换成第K小。然后从根开始遍历,如果当前点的左儿子子树节点数等于K-1的话,就找到了。如果小于,那么往左走。反之往右走。往右走记得要把K扣除比它小的数的数目,即当前点左儿子子树节点数+1.

【代码】

    写得一向龊的splay。。。

    

/**************************************************************
    Problem: 1503
    User: N_C_Derek
    Language: C++
    Result: Accepted
    Time:760 ms
    Memory:5180 kb
****************************************************************/
 
//noi2004郁闷的出纳员
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
int n,m,Min,delt,root,t,ans;
struct node
{
    int l,r,num,father,data;
}tree[200001];
void zig(int x)
{
    int p = tree[x].father;
    tree[x].father = tree[p].father;
    if (tree[p].father != 0)
    {
        if (tree[tree[p].father].l == p)
           tree[tree[p].father].l = x;
        else tree[tree[p].father].r = x;
    }
    tree[p].father = x;
    tree[tree[x].r].father = p;
    tree[p].l = tree[x].r;
    tree[x].r = p;
    tree[p].num -= tree[tree[x].l].num + 1;
    tree[x].num += tree[tree[p].r].num + 1;
}
void zag(int x)
{
    int p = tree[x].father;
    tree[x].father = tree[p].father;
    if (tree[p].father != 0)
    {
        if (tree[tree[p].father].l == p)
           tree[tree[p].father].l = x;
        else tree[tree[p].father].r = x;
    }
    tree[p].father = x;
    tree[tree[x].l].father = p;
    tree[p].r = tree[x].l;
    tree[x].l = p;
    tree[p].num -= tree[tree[x].r].num + 1;
    tree[x].num += tree[tree[p].l].num + 1;
}
void splay(int x)
{
    while (tree[x].father)
    {
        int j = tree[x].father;
        if (tree[j].father == 0)
        {
            if (tree[j].l == x) zig(x);else zag(x);
            break;
        }
        if (tree[tree[j].father].l == j)
        {
            if (tree[j].l == x)
            {
                zig(j);
                zig(x);
            }
            else {
                zag(x);zig(x);
            }
        }else
        {
            if (tree[j].r == x)
            {
                zag(j);
                zag(x);
            }
            else {
                zig(x);zag(x);
            }
        }
    }
    root = x;
}
void Insert(int x)
{
    if (!root) {tree[++t].data = x;tree[t].num = 1;root = t;return;}
    int i = root,j;
    while (i)
    {
        j = i;
        tree[i].num ++;
        if (x < tree[i].data)
            i = tree[i].l;
        else i = tree[i].r;
    }
    if (x < tree[j].data)
        tree[j].l = ++t;
    else
        tree[j].r = ++t;
    tree[t].father = j;
    tree[t].data = x;
    tree[t].num = 1;
    splay(t);
}
void find(int k)
{
    if (k < 1)
    {
        printf("-1\n");
        return;
    }
    int i = root;
    while (tree[i].l || tree[i].r)
    {
        if (k == tree[tree[i].l].num + 1) break;
        if (k < tree[tree[i].l].num + 1)
            i = tree[i].l;
        else
        {
            k -= tree[tree[i].l].num + 1;
            i = tree[i].r;
        }
    }
    printf("%d\n",tree[i].data + delt);
}
void Delete(int k)
{
    int x = root;
    int xx= 0;
    while (x)
    {
        if (tree[x].data < k) {xx = x;x = tree[x].r;}
        else x = tree[x].l;
    }
    if (xx == 0) return;
    splay(xx);
    if (tree[xx].r == 0) {ans += tree[xx].num;root = 0;return;}
    ans += tree[tree[xx].l].num + 1;
    root = tree[xx].r;tree[root].father = 0;
}
int main()
{
    scanf("%d %d",&m,&Min);
    for (int i = 1;i <= m;i ++)
    {
        char ch;
        int k;
        scanf("\n");
        scanf("%c %d",&ch,&k);
        if (ch == 'I')
        {
            if (k >= Min) Insert(k - delt);
        }
        else if (ch == 'F')
        {
            find(tree[root].num - k + 1);
        }
        else if (ch == 'S')
        {
            delt -= k;
            Delete(Min - delt);
        }
        else
            delt += k;
    }
    printf("%d",ans);
}

 

posted @ 2013-01-10 20:22  N_C_Derek  阅读(219)  评论(0编辑  收藏  举报