• 平衡树


    这么久没写平衡树了,再来一发...


    P1486 郁闷的出纳员

    题目描述

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

    输入

    第一行有两个非负整数n和min。n表示下面有多少条命令,min表示工资下界。
    接下来的n行,每行表示一条命令。命令可以是以下四种之一:

    名称 格式 作用
    I命令 I_k 新建一个工资档案,初始工资为k。如果某员工的初始工资低于工资下界,他将立刻离开公司。
    A命令 A_k 把每位员工的工资加上k
    S命令 S_k 把每位员工的工资扣除k
    F命令 F_k 查询第k多的工资

    _(下划线)表示一个空格,I命令、A命令、S命令中的k是一个非负整数,F命令中的k是一个正整数。
    在初始时,可以认为公司里一个员工也没有。

    输出

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

    样例

    .in
    9 10
    I 60
    I 70
    S 50
    F 2
    I 30
    S 15
    A 5
    F 1
    F 2
    .out
    10
    20
    -1
    2
    

    说明

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


    郁闷的是我们吧
    平衡树大裸
    不过难搞的就是那个工资的增减量
    我们存一个变量$ adj ( 每次插进一个结点时把工资减去这个) adj ( 然后每次批量改工资的时候修改这个) adj ( 在批量**减去**工资的时候还要split一下 把标准值加上) adj $再分
    split的时候将达到工资下限的保留,不能达到的的扔进另一个树里面
    离开的人就是那个树的大小
    其余操作都很好搞定
    代码蒯上

    #include<iostream>
    #include<iomanip>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int gotcha()
    {
        register int _a=0;bool _b=1;register char _c=getchar();
        while(_c<'0' || _c>'9'){if(_c=='-')_b=0;_c=getchar();}
        while(_c>='0' && _c<='9')_a=_a*10+_c-48,_c=getchar();
        return _b?_a:-_a;
    }
    const int _ = 100002;
    int seed=19260817;
    inline int ou(){return seed=(1ll*seed*17283)%2147483647ll;}
    int ch[_][2],d[_],rn[_],sz[_],all=0,n,root=0,trash;
    inline void up(int a){sz[a]=sz[ch[a][0]]+sz[ch[a][1]]+1;}
    inline int malloc(int a){sz[++all]=1,d[all]=a,rn[all]=ou();return all;}
    inline int merge(int a,int b)
    {
        if(!a || !b)return a+b;
        if(rn[a]<rn[b]){ch[a][1]=merge(ch[a][1],b),up(a);return a;}
        ch[b][0]=merge(a,ch[b][0]),up(b);return b;
    }
    void split(int now,int k,int &a,int &b)
    {
        if(!now){a=b=0;return;}
        if(d[now]>k)a=now,split(ch[now][1],k,ch[now][1],b);
        else b=now,split(ch[now][0],k,a,ch[now][0]);up(now);
    }
    void insert(int wgs)
    {
        int x,y;split(root,wgs,x,y);
        root=merge(merge(x,malloc(wgs)),y);
    }
    int level(int now,int a)
    {
        while(1)
        {
            if(a==0 || a==sz[ch[now][0]]+1)return now;
            if(a<=sz[ch[now][0]])now=ch[now][0];
            else a-=sz[ch[now][0]]+1,now=ch[now][1];
        }
    }
    int lim;
    int main()
    {
        register int t=gotcha(),a,gone=0,adj=0;
        register char op[3];
        lim=gotcha();
        while(t--)
        {
            scanf("%s",op);a=gotcha();
            if(op[0]=='I' && a>=lim)insert(a-adj);
            else if(op[0]=='F')
                if(a>sz[root])puts("-1");else printf("%d
    ",d[level(root,a)]+adj);
            else if(op[0]=='A')adj+=a;
            else if(op[0]=='S')
                adj-=a,split(root,lim-adj-1,root,trash),gone+=sz[trash];
        }
        printf("%d",gone);
        return 0;
    }
    

    无旋treap大法吼!

  • 相关阅读:
    生成TXT下载并以逗号分隔
    使用javascript绑定键盘enter事件到asp.net的button控件 .
    学习wpf播放视频音频的两种不同方法
    批量修改数据库表的架构sql
    如何修改Sql2005注册服务器名称
    虚拟化之Hypervisor
    JAVA环境配置
    centos系统网卡配置详解
    Kali Linux安装
    Linux扩容新增磁盘分区挂载fdisk
  • 原文地址:https://www.cnblogs.com/finder-iot/p/7650923.html
Copyright © 2020-2023  润新知