题解 P1486 【[NOI2004] 郁闷的出纳员】
P1486 [NOI2004] 郁闷的出纳员
题目大意:
维护一个数据结构,有以下操作:
- 插入一个点,若该点的值小于规定下界,直接删除;
- 把所有点的值加 \(k\) ;
- 把所有点的值减 \(k\) ,若有点得值小于下界,则删除;
- 查询第 \(k\) 大的数,若没有输出 \(-1\) ;
最后还要输出因小于下界被删除的点得个数。
solution:
这熟悉的操作,我们直接上平衡树。对于操作 \(1\) ,直接插入就好了。对于操作 \(2\) 、 \(3\) ,暴力修改时间复杂度不允许,但我们发现加减操作都是对于整体的,所以我们开一个 \(delta\) 来记录整体的加减。在我们插入新点时,把 \(k\) 减去 \(delta\) ,加入到树中。取出点时加上 \(delta\) 。就降低了时间复杂度。
在进行操作 \(3\) 时,我们需要找到大于等于 \(min-delta\) 的最小数。然后删除这段区间。
简单推导一下:
对于 \(\forall k_i\) 满足 \(k_i<min\) 的数会被删掉,但这平衡树中存的是 \(k_i-delta\) 的值,所以有 \(k_i+delta<min\) ,我们要删除的值域为 \(k_i<min-delta\) 。但是我们要找到第一个不被删的点,即右边界的开区间,所以要找大于等于 \(min-delta\) 的最小值的位置作为右端点。
推毕[滑稽]
具体操作是找到右端点,将其转到跟,将左端点转到根的左儿子,这时左端点的右儿子即为要删除的点,清空儿子即可。
操作 \(4\) 是基操,也不说了,但别忘了加上 \(delta\) ,若此时树的大小 \(<k\) 即输出 \(-1\) 。
细节处理:
一定要考虑哨兵产生的影响

浙公网安备 33010602011771号