线段树.
考虑对于给定的数列,如何计算最小修改次数.
若当前数列长度为 $x$ ,则操作一次后会转移到 $x-cnt(x)$ ,其中 $cnt(x)$ 表示数列中有几个 $x$ .
想让数列长度变为 $0$ ,这相当于每个长度都要被删去一次,而 $x$ 可以让 $[x-cnt(x)+1,x]$ 这些长度都被删一次.
于是 $[1,n]$ 内每种数字 $x$ 可以覆盖一段区间 $[x-cnt(x)+1,x]$ ,询问 $[1,n]$ 内有几个位置没被覆盖即为答案.
可以用线段树维护每个位置被覆盖的次数,询问最小值以及最小值出现的次数即可得到答案.
现在考虑如何支持修改,单点修改可以直接删掉原来的线段,加上新的线段.
整体 $+1,-1$ 可以直接对全局维护偏移量标记 $\Delta$ ,询问 $[1,n]$ 时改为询问 $[1-\Delta,n-\Delta]$ 即可.
注意整体 $+1,-1$ 时,可能会导致 $n$ 与 $n+1$ 交换,此时需要修改它们的贡献.
时间复杂度 $O(n\log n)$ .
1 | //%std |