HYSBZ 1503 郁闷的出纳员 (Splay树)
题意:
作为一名出纳员,我的任务之一便是统计每位员工的工资。但是我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。
工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。
每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。
老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第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树)的更多相关文章
- bzoj 1503郁闷的出纳员(splay)
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 11759 Solved: 4163[Submit][Stat ...
- [BZOJ 1503]郁闷的出纳员(fhq treap)
[BZOJ 1503]郁闷的出纳员 题面 第一行有两个非负整数n和min.n表示下面有多少条命令,min表示工资下界. 接下来的n行,每行表示一条命令.命令可以是以下四种之一: 名称 格式 作用 I命 ...
- BZOJ 1503: [NOI2004]郁闷的出纳员 splay
1503: [NOI2004]郁闷的出纳员 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作 ...
- 洛谷 1486/BZOJ 1503 郁闷的出纳员
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 13866 Solved: 5069[Submit][Stat ...
- NOI2004 郁闷的出纳员 Splay
郁闷的出纳员 [问题描述] OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常, ...
- BZOJ 1503 郁闷的出纳员 (treap)
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 13370 Solved: 4808[Submit][Stat ...
- BZOJ 1503 郁闷的出纳员(splay)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503 题意:给出一个数列(初始为空),给出一个最小值Min,当数列中的数字小于Min时自动 ...
- 【BZOJ1503】 [NOI2004]郁闷的出纳员 splay
splay模板题,都快把我做忧郁了. 由于自己调两个坑点. 1.删除时及时updata 2.Kth 考虑k满足该点的条件即r->ch[1]->size+1<=k && ...
- BZOJ 1503 郁闷的出纳员(平衡树)(NOI 2004)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1503 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作 ...
随机推荐
- c#-关于自动属性的思考
参考:c#-关于自动属性的思考 我的理解:自动属性跟 公有字段 一模一样,编程习惯而已.目前是这么认为的. 自动属性:public string Name{ get; set } 公有字段:pub ...
- NOIP前的水题记录
CF147B Smile House 二分+矩阵快速幂,注意一下储存矩阵相乘结果的矩阵,初始化时,a[i][i]=-inf(而其他都可以a[i][i]=0,为了保证答案的可二分性). CF715B C ...
- Linux 系统开机启动项清理
一般情况下,常规用途的 Linux 发行版在开机启动时拉起各种相关服务进程,包括许多你可能无需使用的服务,例如蓝牙bluetooth.Avahi. 调制解调管理器ModemManager.ppp-dn ...
- 重新安装VMware10提示"The Msi '' Failed"问题解决方案
想把虚拟机软件升级以下,没想到卸载的时候不干净,再安装的时候总提示让我先卸载旧版本但实际上旧版本已经卸载过了,这里又没法再卸载一次,所以就提示”The MSI '' failed“ 显然,安装程序还是 ...
- auto_ptr智能指针
C++的auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理. 使用std::auto_ptr,要#include <memory>.
- VC++、MFC
VC++.MFC最好的开源项目 介绍:介绍一下用VC++/MFC写的最好的开源项目. Sourceforge.net中有许多高质量的VC++开源项目,我列举了一些可以作为VC++程序员的参考. 正文: ...
- HashSet重复元素判断
HashSet不能添加重复的元素,当调用add(Object)方法时候,首先会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素:如果已存在则调用Object ...
- A. Hulk
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
- linux中目录操作<1>
一.目录的权限 (1)目录文件的访问权限分为三组,分别为所有者,用户,其他.每个权限组的权限位有3个,分别为读.写.执行. 注意:可以使用stat函数得到目录文件的状态信息.权限为在stat结构中st ...
- ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 21. Model 验证 Again
深入的将Model验证 手动添加验证的错误 view里面显示每个属性的验证错误信息 显示整个model级别错误 自定义验证 如果业务逻辑需要比较复杂的验证.而且这个验证逻辑可能到处复用的话就应该考虑使 ...