题解 P1486 【[NOI2004] 郁闷的出纳员】

P1486 [NOI2004] 郁闷的出纳员

题目大意:

维护一个数据结构,有以下操作:

  1. 插入一个点,若该点的值小于规定下界,直接删除;
  2. 把所有点的值加 \(k\)
  3. 把所有点的值减 \(k\) ,若有点得值小于下界,则删除;
  4. 查询第 \(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\)

细节处理:

一定要考虑哨兵产生的影响

posted @ 2021-07-29 20:15  Mr_think  阅读(56)  评论(0)    收藏  举报