P4396 [AHOI2013]作业 题解
一道莫队好题。
我们需要考虑的是如何去统计一个区间内的符合题意的答案。
这里有两种做法:
做法一:树状数组/线段树。
我们可以开一个值域树状数组/值域线段树,在每一次莫队增/删的时候我们在对应位置进行单点修改操作,维护一下一个区间内的数的个数以及不同数的个数。
最后统计答案的时候,进行一次区间查找操作。
时间复杂度分析(不计预处理复杂度):
莫队转移复杂度是 \(O(n \sqrt{m})\),其中块长是 \(\dfrac{n}{\sqrt{m}}\),块数是 \(\sqrt{m}\),在转移过程中线段树单点修改和区间查询复杂度都是 \(O(\log n)\),因此总复杂度是 \(O(n \sqrt{m} \log n + \sqrt{m} \log n) \to O(n \sqrt{m} \log n)\)。
由于 \(n,m\) 同阶,上述复杂度可以记为 \(O(n \sqrt{n} \log n)\)。
做法二:
发现上述做法对于修改操作和查询操作复杂度是一样的,都是 \(O(\log n)\)。
但是显然查询复杂度 \(O(\sqrt{m})\) 远小于转移复杂度 \(O(n \sqrt {m})\),因此我们可以考虑使用一种奇怪的数据结构使得其能够 \(O(1)\) 修改,\(O(?) \leq O(n)\) 修改。
这里就有一种数据结构叫做值域分块。
对于修改操作,我们直接在对应位置上修改,复杂度 \(O(1)\)。
查询的时候,我们进行一次区间查询,复杂度 \(O(\sqrt{V})\),\(V\) 是值域。
时间复杂度分析:
转移操作总复杂度是 \(O(n \sqrt{m})\),修改操作 \(O(1)\)。
查询操作总复杂度是 \(O(\sqrt{m})\),单次查询 \(O(\sqrt{V})\)。
因此总复杂度是 \(O(n\sqrt{m}+\sqrt{mV})\)。
由于 \(n,m,V\) 同阶,上述复杂度可以简记为 \(O(n\sqrt{n}+\sqrt{n^2})=O(n\sqrt{n}+n)=O(n\sqrt{n})\),发现比做法一少了一个 \(\log\)。
作者采用的是第二种做法。