首先考虑没有 add 操作和 del 操作怎么做。
注意到箱子始终都是推在一边的,故只需要判断第 x 行的箱子个数是否不少于 y 或 m−y+1 便可确定 (x,y) 是否有箱子。
则考虑将维护每一行是否有箱子的线段树按照每一行的箱子个数从大到小可持久化。
现在的问题就在于给定一个全是 0/1 的线段树,如何找到给定位置的前驱 0 或后继 0。
实际上可以通过维护 0 的位置的最值解决,但是由于一些问题此题不可考虑维护最值解决这个问题,于是考虑维护和。
则只需要找到第一个位置使得其到给定位置的和不等于这个位置与给定位置之间的长度即可。
显然可二分,注意找的时候要删去另一边的贡献(前驱则删去给定位置后缀的贡献,后继则删去给定位置前缀的贡献)。
加入修改操作的话,可以先开 m 棵动态开点线段树来维护修改操作,在执行 left 或 right 操作时再合并。
注意到每个修改操作对每一行箱子个数的贡献只有 ±1,故在可持久化线段树上直接修改即可。
代码:
1 |
|