折半警报器/二进制警报器
引入这么一道题:
维护数列,支持单点加;并且某些时刻给出 \(k\) 个位置,在这 \(k\) 个位置之和 \(\ge lim_i\) 的时候输出操作编号并删除。
折半警报器
考虑这样一件事:一个报警器报警的必要条件是 \(\max\{a_{p_i}\}\ge \left\lceil\dfrac{lim}{k}\right\rceil\)。
于是我们往每个 \(p_i\) 里面扔一个 \(\left\lceil\dfrac{lim}{k}\right\rceil\) 的报警器。
每次单点加如果使某个报警器达到了阈值,暴力 check 其所在报警器;如果成功报警,输出并删除;否则考虑设这个报警器剩下 \(w\) 的阈值,显然 \(w\le lim-\left\lceil\dfrac{lim}{k}\right\rceil\),把对应位置里的报警器阈值加上 \(\left\lceil\dfrac{w}{k}\right\rceil\) 即可。
那么,每个报警器最多被重构 \(\log_{\frac{k}{k-1}}lim=\dfrac{\ln lim}{\ln k-\ln(k-1)}=\Theta(\log V)\) 次。使用数据结构维护即可,复杂度做到 \(\Theta(nk\log V(\log n+k))\)。
二进制警报器
尝试用二的幂次描述或修改一下减半报警器。对于一个报警器,我们维护一个 \(h\),当每个监控元素“经过” \(2^h\) 的倍数时报警,如果所有元素都能不报警达到 \(lim\) 那么就将 \(h\gets h-1\)。
复杂度分析懒得放了。跑的比折半快 \(10\) 倍。

浙公网安备 33010602011771号