【BZOJ 1503】[NOI2004]郁闷的出纳员

【链接】 我是链接,点我呀:) 【题意】

在这里输入题意

【题解】

因为所有人工资同时递减。 所以可以设置一个变化值delta. 然后每个人的初始值为k 则把k-delta加入伸展树中。 会发现delta变化之后。 伸展树中每个人的工资就仍然是原先的值+delta

比如 I 2000 delta = 100 则会插入一个1900到伸展树中。

然后delta的值可能会发生变化。

但会发现1900+delta会总是和这个人的当前工资相同 (并且对于每个人都是如此

那么我们只要把min-delta插入到伸展树种。 则比他小的数字都是要离开的人 (把这个min-delta移动到根节点。 然后把它的左子树大小累加一下就好

至于找第k大。 则也是伸展树能够完成的事情。

x-delta插入 以及delta改变之后 x+delta始终是每个人的真实工资这一点很关键。 (很棒的ideal

【代码】

#include <cstdio>
#define which(x) (ch[fa[x]][1]==x)
using namespace std;

int n,mi,delta;

const int N = 1e5 + 200;

int m,fa[N], tot, ch[N][2], root, x, siz[N],value[N];

void push_up(int x)
{
    siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
}

int Rank(int x, int k)
{
    if (siz[ch[x][0]] >= k)
        return Rank(ch[x][0], k);
    else
        if (k == siz[ch[x][0]] + 1)
            return x;
        else
            return Rank(ch[x][1], k - siz[ch[x][0]] - 1);
}

void Rotate(int x)
{
    int f = fa[x];
    bool k = which(x);
    ch[f][k] = ch[x][!k];
    ch[x][!k] = f;
    ch[fa[f]][which(f)] = x;
    fa[ch[f][k]] = f;
    fa[x] = fa[f];
    fa[f] = x;
    siz[x] = siz[f];
    push_up(f);
}

void Splay(int x, int g)
{
    while (fa[x] != g)
    {
        int f = fa[x];
        if (fa[f] == g)
        {
            Rotate(x);
            break;
        }
        if (which(x) ^ which(f))
            Rotate(x);
        else
            Rotate(f);
        Rotate(x);
    }
    if (!g) root = x;
}

void cr(int x,int num)
{
    if (!x){
        root = ++tot;
        siz[tot] = 1;
        value[tot] = num;
        return;
    }
    if (ch[x][num>value[x]]==0){
        ch[x][num>value[x]] = ++tot;
        value[tot] = num;
        fa[tot] = x;
        siz[tot] = 1;
    }else
        cr(ch[x][num>value[x]],num);
    push_up(x);
}


int main()
{
    //freopen("D:\\rush.txt","r",stdin);
    long long ans = 0;

    scanf("%d%d",&n,&mi);
    for (int i = 1;i <= n;i++){
        int k;
        char s[5];
        scanf("%s",s);
        if (s[0]=='I'){
            scanf("%d",&k);
            if (k<mi) continue;
            cr(root,k-delta);
            Splay(tot,0);
        }else if (s[0]=='A'){
            scanf("%d",&k);
            delta+=k;
        }else if (s[0]=='S'){
            scanf("%d",&k);
            delta-=k;
            cr(root,mi-delta);
            Splay(tot,0);
            ans+=siz[ch[tot][0]];
            root = ch[tot][1];
            fa[root] = 0;
        }else if (s[0]=='F'){
            scanf("%d",&k);
            if (k>siz[root]){
                printf("%d\n",-1);
            }else{
                int x = Rank(root,siz[root]-k+1);
                Splay(x,0);
                printf("%d\n",value[x]+delta);
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值