出纳员

BZOJ 1503 郁闷的出纳员 treap

試著忘記壹切 提交于 2020-02-16 07:47:38
真的,想引用一下另外以为大神的博客, 这道题改成郁闷的博主好了, (调了3个小时后弃疗)。 不过这道题之所以没能写好,我觉得有个原因也是经验不够,太单纯了,题目叫我脚上某个数,减去某个数,难道我就真的去加去减吗(肯定TLE的)? 看了别人的博客,我才恍然大悟,有延时操作这种神奇的东西。 简单形容一下这道题的延时操作吧! 假设最低工资标准为 low, 用一个变量a, 如果要对数列加上某个数b 的话, 就 a += b, 如果要减去某个数 b , 就 a -= b, 删除的时候要怎么办呢? 这是要删去比 low - a 小的数,(因为如果a为正意味着数列中的数加上了a,其实相当于最低工资标准减去a)。 那如果要插入某个数b呢! 就要插入 b - a; 因为a是对之前的值处理的结果,与b无关,而接下来要把b和之前的值一视同仁,所以要减去,即把b插入队列后,b会自动加上a,所以要把a减去。 这就是延时操作。另外一个就是删除操作,其实也不难(真不明白,一开始为什么我要把函数写成没返回值的而且直接处理后赋值就行了, 我干嘛把右节点旋上来,傻啊!)too young too simple。 加油!看来还得多练(还有要看题,人家明明说了,如果初始工资小于最低工资标准,人家会离开的。我哭了TAT) 1 #include<cstdio> 2 #include<iostream> 3 #include

[NOI2004]郁闷的出纳员(Splay)

寵の児 提交于 2020-02-02 00:29:08
[NOI2004]郁闷的出纳员(Splay) 题目描述 首先这题一看就是道平衡树。我们来考虑如何用平衡树实现这个操作 首先,如果要给员工加工资或者扣工资,平衡树肯定是实现不了。我们要用一个变量来记录目前加了多少工资,我们可以先叫它 l a z y lazy l a z y ,我们每个询问在取出的时候加上 l a z y lazy l a z y 就好了。 但是如果一个员工是新加入公司的,那么前面给员工加的工资它肯定是享受不到,为了解决这个问题,我们在每个员工加入时,他的工资要减去 l a z y lazy l a z y 这个问题解决了,再结合平衡树的一些知识,这道题就差不多了。我们来总结一下这里的操作怎么实现: 加入员工:直接在平衡树里加入一个节点即可。 加工资:直接 l a z y + = k lazy += k l a z y + = k 即可 扣工资:首先 l a z y − = k lazy -= k l a z y − = k 然后我们在平衡树中插入一个节点 l a z y − m i n n lazy - minn l a z y − m i n n (minn是工资下界,也就意味着比这个工资低的都要删除) 我们将这个点旋转到根,并直接将根的左子树全部歼灭(将根的左儿子设为0) 第k大:基本平衡树操作 贴个代码` # include <bits/stdc++.h>

bzoj1503[NOI2004]郁闷的出纳员 treap

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

bzoj1503: [NOI2004]郁闷的出纳员 fhqtreap版

我只是一个虾纸丫 提交于 2020-01-30 08:17:47
这道题写法和之前差不多 但是fhqtreap在加点的时候为了同时维护大根堆以及二叉排序树的性质所以插入时也要注意分裂 fhqteap需要判断指针是否为空 不然就会re 这个我调了很久 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=150000; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,sum,mn,leave,delta; struct node{ node *l,*r; int sz,v,rnd; void init(int w){sz=1; v=w; rnd=rand();} void up(){ sz=1; if(l) sz+=l->sz; if(r) sz+=r->sz; } void split(node*&lw,node*&rw,int w){ if(!this){lw=0; rw=0; return ;} if(w<=v){ l->split

[NOI2004]郁闷的出纳员

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

P1486 [NOI2004]郁闷的出纳员

一世执手 提交于 2019-11-30 04:27:44
题目链接 这道题需要动态插入,删除,求排名,看到这就想到了平衡树。由于本人只会splay,所以就用splay来做这道题,这道题插入和删除都是模板,但是题中还有一个比价坑的地方就是工资的调整。但我做不到在平衡树上修改点权。如果每一个都去插入和删除的复杂度显然非常高。看了题解发现,可以维护一个变量来记录每次工资调整时的值delta,像这样的话我们插入的k值就应该是k-delta,为什么要这样做呢,因为我们显然无法修改之前的点权,这样一来就是维护一个相对的大小。 重点还有如何把工资低于下界的人都删去。我们在操作之前提前插入两个哨兵节点+/-inf,这样可以避免操作时的错误,这是一个技巧,需要记住。在删除的时候把权值为-inf的点旋转到根节点,然后将全值为下界的点转到根节点的右儿子上,这是根节点右儿子的左儿子就是比工资下界小的所有节点,然后直接删除即可。 注意再求排名的时候要减去两个插入的哨兵节点。 代码如下: #include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; const int inf=0x7fffffff; int n,minn; char opt[maxn]; int key[maxn],fa[maxn],cnt[maxn],size[maxn],ch[maxn][2]; int rt,sz; int

[NOI2004]郁闷的出纳员

家住魔仙堡 提交于 2019-11-27 22:18:25
题目描述 有一个公司,有四种操作: 1.拉一个人进入公司,有初始工资 2.每个人的工资加上x 3.每个人的工资减去x 4.查询第k大的工资 当一个人工资低于m时他就会立即离开公司。 要求对于询问输出答案,最后输出离开的人的个数。 题解 查询第k大就用平衡树搞。 主要要解决的就是如何高效的帮助人离开,可以想到找到第一个满足留在公司的人,他前面的人都不满足删掉即可。 2.3操作肯定是懒惰标记搞,因为是每个人平等的(同加同减),所以不会搞乱相对大小,在访问这个点的时候信息是更新好了的。用ret记录第一个满足的人,如果这个人的工资满足,ret就是这个人,然后往左儿子走,不然走右儿子。(可能有点绕,需要理解) 如果ret没记录说明全部都要走(好惨),这时特判搞一搞就好。记录了就旋到根,去掉根的左儿子。 有些地方要注意边界,因为splay可能没元素。 因为工资可能一样,所以要多记录一个num。 在在splay里面走的时候要push_down!!!!插入,删除,查k大 一个人初始工资不满足离开不加入最后答案(坑死我)。 #include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,m,root,cnt,ans; struct Splay{ int fa,s[2],size,tag,val,num; }tr