首先考虑一个全局的做法。
对于这个 1 号操作,我们有两种方式做:
将所有 ≤x 的数加上 x,然后全局打上一个减法标记。
将所有 >x 的数减去 x 。
如果当前全局最大值是 lim ,那么第一种方式相当于用 x 次修改将 lim 减去 x ,第二种方式相当于用 lim−x 次修改将 lim 减去 x 。
因为值域只有 \(S=105\) 级别,考虑一个修改次数也是 \(O(S)\) 级别的做法。
容易发现两种方式各有优劣:第一种方式如果一直无脑加的话,容易发现,当 \(x>lim/2\) 的时候,就不容易确定上界的位置了.
但是如果 \(x≤lim/2\) ,就可以放心减,因为这个时候 \(lim\) 减去$ x $后还是最大值。
那么对于 \(x>lim/2\) 的部分怎么做呢?这个时候可以考虑用第二种方法,然后将 \(lim\) 定为 \(x\) 。这个时候简单计算一下可以发现没有多余操作了。
接下来就是维护颜色块,考虑用并查集维护,这样十分方便合并。
拓展到区间的做法,将序列分块,每个块用一个并查集然后照做就是了。但是这样空间开不下,所以要离线,然后一个一个块的处理贡献。
整块修改:按照上面的做法即可,修改权值相当于合并并查集。
散块修改:重构并查集,重构的复杂度是 O(\(\sqrt n\)) 的,是正确的。
整块查询:直接查询对应并查集的大小即可。
散块查询:暴力枚举这些位置,然后找到它们归属的并查集的数是否等于 x 即可。