题意:

  作为一名出纳员,我的任务之一便是统计每位员工的工资。但是我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。

  工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。

  每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。

  老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。

  

思路:

  (1)插入比较简单,只要允许重复值的存在就行了。但是下面的操作需要维护一个变化量add,所以插入之前要先减去add再插入。若不这样做,由于每次加工资只是针对当前的员工,而之前的加减工资并不没有针对新员工,所以新员工并不应该享受到老员工的加减工资福利。

  (2)集体加工资,可以用一个全局变量统计当前所有员工的工资变化量add。

  (3)扣工资同加工资一样,用同一个变量统计。但是有人可能会因为此次扣工资而离开公司,所以要及时清理掉这些人。方法是,如果当前员工有人的工资刚好等于min,那么将其伸展到根,再删除其左子树即可(注意,可能有多个人的工资等于min,那么你删除时,要保证根的左子树中并不存在工资为min的人,即需要将最左的min伸展到根)。否则,插入一个工资为min的点,再将其伸展到根,同样删除左子树,然后再删除自己。注意,所有人的工资得加上所维护的工资变化量。

  (4)查询第k多比较简单,只要维护左子树的节点数量以及右子树的节点数量。如果在左子树中,则k要减去工资大于本节点的人数,再往下找。如果在右子树中,仍然用的是k来找。

  还有一点很神奇的地方就是,每次插入新元素都是插到叶子节点,但是插入过程我们不需要更新插入路径上面的点的左右孩子数量,因为一插入完毕之后立刻就splay到根了,这样子相当于插入之前的树自己在维护孩子数量而已,而新节点从叶子伸展到根自然会更新孩子数量了。所以只需要在rotate中维护孩子数量即可。

 #include <bits/stdc++.h>
#define pii pair<int,int>
#define INF 0x7f7f7f7f
#define LL long long
using namespace std;
const int N=;
int root, node_cnt, ans, add, del;
struct node
{
int pre, val;
int son[]; //子树中有多少个节点。
int ch[];
}nod[N]; int create_node(int v,int far) //返回节点下标
{
nod[node_cnt].val=v;
nod[node_cnt].pre=far;
nod[node_cnt].ch[]=;
nod[node_cnt].ch[]=;
nod[node_cnt].son[]=;
nod[node_cnt].son[]=;
return node_cnt++;
} void init()
{
add=root=node_cnt=;
create_node(INF, ); //0号点是不要的
} void Rotate(int t, int d) //d为方向,0是左旋,1是右
{
int far=nod[t].pre;
int son=nod[t].ch[d]; //far的孩子
int gra=nod[far].pre; //far的父亲 nod[son].pre=far;
nod[t].pre=gra;
nod[far].pre=t; nod[far].ch[d^]=son;
nod[t].ch[d]=far;
nod[gra].ch[nod[gra].ch[]==far]=t; //子树中的节点要更新
nod[far].son[d^]=nod[t].son[d];
nod[t].son[d]+=+nod[far].son[d]; //别忘了还有far也是个节点
} void Splay(int t,int goal) //将t转为goal的任一孩子
{
while( nod[t].pre!=goal ) //t还不是根
{
int f=nod[t].pre, g=nod[f].pre;
if( g==goal ) Rotate( t, nod[f].ch[]==t ); //父亲就是根s,旋1次
else
{
int d1=(nod[f].ch[]==t), d2=(nod[g].ch[]==f);
if( d1==d2 ) //两次同向旋转
{
Rotate( f, d1);
Rotate( t, d1);
}
else //两次反向旋转
{
Rotate( t, d1);
Rotate( t, d2);
}
}
}
if(!goal) root=t; //时刻更新树根
} int Insert(int t, int v)
{
int q=-;
if( v>nod[t].val ) //右边
{
if( nod[t].ch[]== ) q=(nod[t].ch[]=create_node(v, t));
else q=Insert(nod[t].ch[], v);
}
else //左边,相等时插左边
{
if( nod[t].ch[]== ) q=(nod[t].ch[]=create_node(v, t));
else q=Insert(nod[t].ch[], v);
}
return q;
} int Find(int t,int v) //找到值为v的,若没有,则返回-1
{
while( t )
{
if(nod[t].val==v)
{
int r=Find(nod[t].ch[], v); //找到最左边的那一个,即保证t的左子树中没有等于v的点。
if(r==-) return t;
else t=r;
}
if( nod[t].val<v ) //左边
t=nod[t].ch[];
else
t=nod[t].ch[];
}
return -;
} void Delete(int t, int limit) //将所有工资低于限额的,删去该子树。
{
//先找找看有没有等于这个值的。
int r=Find(root, limit-add);
if(r==-) //没有找到,则插入这样的值,Splay到顶,然后删去此点的左子树
{
Splay( Insert( root, limit-add ) , );
del+=nod[root].son[];
int right=nod[root].ch[]; //再删去此节点(即根)
if(right==) init(); //全部删完,没有员工
else nod[right].pre=, root=right;
}
else //找到了最左端的一个。
{
Splay(r, ); //旋转到顶,删去左子树。
del+=nod[root].son[];
nod[root].son[]=;
}
} int Query(int t,int k) //查找第k多
{
if( nod[t].son[]+nod[t].son[]+<k ) return -; //整棵树都还没有k个
while( nod[t].son[]!=k- )
{
if(nod[t].son[]>k-) t=nod[t].ch[]; //在右孩子中
else //在左孩子中
{
k-=nod[t].son[]+;
t=nod[t].ch[];
}
}
Splay(t, );
return add+nod[t].val;
} int main()
{
//freopen("input.txt", "r", stdin);
int n, limit, t;char c;
while(cin>>n>>limit)
{
init();
del=; //离开员工的人数
for(int i=,a=; i<n; i++,a=)
{
while( !isalpha(c=getchar())) ;
scanf("%d", &a);
if(c=='I' && a>=limit) Splay( Insert(root, a-add), ); //插完就伸展。新员工要减掉个add。再伸展到根。
else if(c=='A') add+=a; //全体加工资
else if(c=='S') add-=a,Delete(root, limit); //全体扣工资,有人可能因为此次扣工资而离开公司。
else if(c=='F') printf("%d\n", Query(root, a));
}
printf("%d\n", del);
}
return ;
} AC代码

AC代码

HYSBZ 1503 郁闷的出纳员 (Splay树)的更多相关文章

  1. bzoj 1503郁闷的出纳员(splay)

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 11759  Solved: 4163[Submit][Stat ...

  2. [BZOJ 1503]郁闷的出纳员(fhq treap)

    [BZOJ 1503]郁闷的出纳员 题面 第一行有两个非负整数n和min.n表示下面有多少条命令,min表示工资下界. 接下来的n行,每行表示一条命令.命令可以是以下四种之一: 名称 格式 作用 I命 ...

  3. BZOJ 1503: [NOI2004]郁闷的出纳员 splay

    1503: [NOI2004]郁闷的出纳员 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作 ...

  4. 洛谷 1486/BZOJ 1503 郁闷的出纳员

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 13866  Solved: 5069[Submit][Stat ...

  5. NOI2004 郁闷的出纳员 Splay

    郁闷的出纳员 [问题描述] OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常, ...

  6. BZOJ 1503 郁闷的出纳员 (treap)

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 13370  Solved: 4808[Submit][Stat ...

  7. BZOJ 1503 郁闷的出纳员(splay)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503 题意:给出一个数列(初始为空),给出一个最小值Min,当数列中的数字小于Min时自动 ...

  8. 【BZOJ1503】 [NOI2004]郁闷的出纳员 splay

    splay模板题,都快把我做忧郁了. 由于自己调两个坑点. 1.删除时及时updata 2.Kth 考虑k满足该点的条件即r->ch[1]->size+1<=k && ...

  9. BZOJ 1503 郁闷的出纳员(平衡树)(NOI 2004)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作 ...

随机推荐

  1. android.annotation.SuppressLint

    Lint是一个静态检查器,它围绕Android项目的正确性.安全性.性能.可用性以及可访问性进行分析.它检查的对象包括XML资源.位图.ProGuard配置文件.源文件甚至编译后的字节码. Lint包 ...

  2. fasttext(1) -- 认识 fasttext 和 初步使用

    fastText 的 Python接口:https://github.com/salestock/fastText.py (1) fasttext 简介:FastText是Facebook开发的一款快 ...

  3. 【前端】CentOS 7 系列教程之四: 配置 git 服务器自动部署

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/linux_4.html 安装pm2守护进程,备用 npm install -g pm2 创建/srv/www文件夹 ...

  4. 仿照 QQ 的 cell 的左滑删除、置顶、标记未读效果

    侧滑删除.置顶.取消关注,在iOS8之前需要我们自定义,iOS8时苹果公司推出了新的API,UITableViewRowAction类,我们可以使用该类方便的制作出如下图的效果. 下面是实现的主要代码 ...

  5. API接口文档的撰写

    接口文档: 要写:接口简介.请求参数.返回结果.注意事项. 下面以“喜马拉雅的 ‘圈子’ ”为例子: 接口一 (1)接口简介 http://ipservice.mogujie.com/ipservic ...

  6. servlet 3 文件上传

    1.up.jsp <%@ page language="java" pageEncoding="utf-8"%> <form action=& ...

  7. 看鸟哥的Linux私房菜的一些命令自我总结(二)

    -关于执行文件路径的变量  $PATH -查看文件与目录  ls -a  :全部的文件,连同隐藏文件一起列出来 -d  :仅列出目录本身,而不是列出目录内的文件数据 -i   :列出inode号码 - ...

  8. Go语言中的代码重用 - 继承还是组合?

    故事要从我在一个项目中,想要假装的专业一点而遇到的一个陷阱说起. 代码重用 在这个项目中,我们已经有了类似如下的代码: package main import ( "fmt" ) ...

  9. 实例List化

    实现了__iter__()的实例虽能用于for循环,看似像list,但并不能将其当做list来使用,比如,Fib()[5]还是报错 可通过实现__getitem__()方法,:来实现让实例像list那 ...

  10. Codeforces Round #513解题报告(A~E)By cellur925

    我是比赛地址 A:Phone Numbers $Description$:给你一串数字,问你能组成多少开头为8的11位电话号码. $Sol$:统计8的数量,与$n$%11作比较. #include&l ...