[BZOJ1503]郁闷的出纳员 做题笔记

10 篇文章 0 订阅

题目来源:http://www.lydsy.com/JudgeOnline/problem.php?id=1503

1、首先,维护一个全局变量del,表示全局加多少。插入时要减去del,查找时要加上del,仔细领会一下。
2、删除时,找到工资比最低限小的工资最高的工人,把他旋转到根,然后删除他和左子树!
3、这题的查找是第K大,而不是第K小,要注意第K大的写法。
4、坑!这题说如果一个工人的初始工资比最低限小,那他就会立即离开,这个离开的工人就当是被UFO抓走了,不算在离开的工人之列!

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=101000;
int n,del=0,low;
int leave=0;
struct Splay {
    int ch[N][2],f[N],root,cnt;
    int a[N],c[N],s[N];
    int grow (int k,int fa) {
        int x=++cnt;
        a[x]=k,s[x]=c[x]=1;
        ch[x][0]=ch[x][1]=0;
        f[x]=fa;
        return x;
    }
    void pushup (int x) {
        s[x]=s[ch[x][0]]+s[ch[x][1]]+c[x];
    }
    void rotate (int x) {
        int y=f[x],opt;
        if (ch[f[x]][0]==x) opt=0;
        else opt=1;
        ch[y][opt]=ch[x][!opt];
        if (ch[x][!opt]) f[ch[x][!opt]]=y;
        f[x]=f[y];
        if (root==y) root=x;
        else if (ch[f[y]][0]==y) ch[f[y]][0]=x;
            else ch[f[y]][1]=x;
        f[y]=x,ch[x][!opt]=y;
        pushup(y),pushup(x);
    }
    void splay (int x,int to=0) {
        while (f[x]!=to) {
            if (f[f[x]]==to) rotate(x);
            else if ((ch[f[f[x]]][0]==f[x])
                ==(ch[f[x]][0]==x))
                rotate(f[x]),rotate(x);
            else rotate(x),rotate(x);
        }
    }
    void insert (int k) {
        if (root==0) root=grow(k,0);
        else {
            int x=root;
            while (x) {
                if (k==a[x]) { c[x]++;break; }
                else {
                    int &y=(k<a[x]?ch[x][0]:ch[x][1]);
                    if (!y) 
                        { x=y=grow(k,x);break; }
                    else x=y;
                }
            }
            splay(x);
        }
    }
    int findval (int k) {//返回k的rank,注意返回值<=rank(k)
        int x=root,ans=0;
        while (x) {
            if (k==a[x]) return ans+s[ch[x][0]]+1;
            else if (k<a[x]) x=ch[x][0];
            else ans+=s[ch[x][0]]+c[x],x=ch[x][1];
        }
        return ans;
    }
    int findkth (int k) {//返回第K大的工资,注意写法
        int x=root;
        while (x) {
            if (k>=s[ch[x][1]]+1&&k<=s[ch[x][1]]+c[x])
                return a[x];
            else if (k>s[ch[x][1]]+c[x]) k-=s[ch[x][1]]+c[x],x=ch[x][0];
            else x=ch[x][1];
        }
        return -1-del;
    }
    int myfind (int k) {//找到rank为k的结点的位置
        int x=root;
        while (x) {
            if (k>=s[ch[x][0]]+1&&k<=s[ch[x][0]]+c[x])
                return x;
            else if (k<s[ch[x][0]]+1) x=ch[x][0];
            else k-=s[ch[x][0]]+c[x],x=ch[x][1];
        }
        return 0;
    }
    void erase (int k) {
        int x=myfind(k);
        splay(x);
        leave+=s[ch[x][0]]+c[x];
        if (ch[x][1]) {
            root=ch[x][1];
            f[ch[x][1]]=0;
            pushup(root);
        }
        else root=cnt=0;
    }
}splay;

int main () {
    char s[10];int x;
    scanf("%d%d",&n,&low);
    for (int i=1;i<=n;i++) {
        scanf("%s %d",s,&x);
        if (s[0]=='I') {
            if (x>=low)  splay.insert(x-del);
            //else leave++;这里是要坑死人啊!
        }
        if (s[0]=='A') del+=x;
        if (s[0]=='S') {
            del-=x;
            int tmp=splay.findval(low-del-1);//找到比最低工资线小的工资最高的工人的排名
            if (tmp) splay.erase(tmp);
        }
        if (s[0]=='F') printf("%d\n",splay.findkth(x)+del);
    }
    printf("%d\n",leave);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值