(强制在线)单点修,区间第 \(k\) 小
-
首先有一个简单的序列分块+值域二分做法:
-
序列分块,对每个块建值域树状数组。
-
修改时暴力修改,\(O(\log)\)。
-
询问时将两侧散块合并建一个虚块,然后在值域上二分,在每块内查询,\(O(B\log+num\log^2)\)。
-
显然这是可平衡的,令 \(B=num\log\),解得 \(B=\sqrt{n\log}\),\(num=\frac{\sqrt{n}}{\sqrt{log}}\),代入得复杂度为 \(O((n\log)^\frac{3}{2})\),但意义不大。
-
考虑优化。使用多树二分,可以去一只 \(\log\),也使得复杂度自平衡,时间复杂度为 \(O(n\sqrt{n}\log)\)。
-
-
如果修改的值不强制在线,有一个美妙的序列分块套值域分块做法:
-
序列分块。然后值域分块,开桶(开不下就开哈希表)\(t_{i,j}\) 表示前 \(i\) 个序列块中有多少个 \(j\),并维护 \(s_{i,j}\) 表示前 \(i\) 个序列块中,第 \(j\) 个值域块中有多少个数。
-
修改时暴力修改。暴力枚举后方序列块的 \(s,t\),复杂度为 \(O(num)\)。
-
询问时,将两侧散块合并建一个虚块,将中间的整块也合并进去,我们只关心这个虚块中第 \(j\) 个值域块有多少个数,所以可以利用 \(s\) 的差分性快速处理整块。然后从小到大暴力枚举答案在哪个值域块内,直到找到为止。接下来在这个值域块内暴力枚举答案即可。\(O(B_s+num_r+B_r)\),\(s\) 指 sequence 序列,\(r\) 指 range 值域。因此需要修改的值可以离线,否则表现还不如上面那个。显然其复杂度已经平衡了。
-
区间修,区间查 \(>k\) 的个数
-
本题有一个可以交的改版 UOJ #435。
-
序列分块,发挥懒标记作用。
-
修改时,对散块暴力修改之后维护一个有序副本,\(O(B\log)\);对整块直接打 tag,\(O(num)\)。
-
询问时,对散块暴力枚举,\(O(B)\);在整块上二分,注意这里 \(k\) 要减去对应的 tag(原本是 \(>k\),现在是 \(>k-tag\)),\(O(num\log)\)。
-
故总复杂度为 \(O(n\sqrt{n}\log)\),其已经平衡。
-
如果值域较小,譬如修改为 \(\pm 1\),则可以将二分改成值域分块。具体地,维护 \(s_{i,j}\) 表示第 \(i\) 个块中前 \(j\) 个值域块有多少个数和 \(t_{i,j}\) 表示前 \(i\) 个块中恰为 \(j\) 的有多少个数,...好像不行啊。tag 不统一。单点修大概就可以。但是 这篇博客 说可以,我不会啊...如果有人看到而且会的话,求教。
-