二进制警报器

我们希望在线解决如下形式的问题:

给定长度为 n 的数组和 q 次操作,每次操作如下:

  • 给数组一个位置加 v
  • 给定不超过 k 个位置,要求在数组这些位置的总和超过 v 的时候输出该操作的编号。

众所周知,折半警报器能在均摊做到 O(1)O(k2logqlogV)xy 表示操作一复杂度为 x,操作二复杂度为 y)。但我发现了一个 O(1)O(klogV) 的算法,我们就称其为 "二进制警报器" 吧。

对于一个二操作,设其对应位置为 pos1,...,posd。对于该操作,维护一个阈值 h,只要 aposi 的值经过(axax+w 的时候,我们认为它经过了 (ax,ax+w]2h 的倍数时 "报警"。如果目前的 h 能让所有 aposi 在都不报警的前提下总和超过 v,那么将 h 降低 1

对于每个 h=h0,报警次数总和是不超过 O(k) 的:h 降到 h0 时,vi=1kaposi 应是 O(k2h0) 的;而一个元素报警两次时,它必然增加了至少 2h0

对每个 (位置,h) 开个 vector 维护警报器并利用二进制优化修改时找报警器的复杂度,复杂度是 O(1)O(klogV)

这个结构能对我目前看到的所有减半警报器题目做出优化:

  • 2019-2020 ICPC Asia Hong Kong Regional Contest I:直接的应用,能做到 O(n+mlogV)
  • THUPC 2021 鬼街:直接的应用,能做到 O(n+qω(n)logV)
  • 300iq Contest 2 F:把 vector 改成链表,结合启发式合并可以做到 O((n+m)logV)
  • 2022 CCPC Mianyang Onsite B:这题要难优化一些。考虑直接建线段树,然后将每个人的需求拆到线段树的节点上。这样能做到修改 O(logn),但是查询要 O(log2n)。考虑平衡复杂度,把线段树的二叉改成 logn 叉,并对线段树的每个儿子区间都维护其总和。这样我们就能将每个人的需求拆到 O(lognloglogn) 个点上了,而一次修改只会修改 O(log2nloglogn) 个节点。总复杂度 O(nlog2nloglogn)
  • EZEC Round 12 F:和上一题类似,建立多叉树平衡复杂度,O(mlognlogVloglogV)
posted @   zhoukangyang  阅读(1219)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
主题色彩