ICPC2023沈阳K
https://codeforces.com/gym/104869/problem/K
DS题尽量进一步思考,简化维护过程
权值线段树上二分
首先得出一个显然的转化:对于每次操作,求出此次下所有正数从小到大的前缀和的第一次大于所有负数和的绝对值的位置即为答案。
1|0赛时做法
既然要求每次都求a升序下的前缀和,很显然的想到维护ai的权值线段树,然后对这个位置二分答案,时间复杂度
其实是完全能过的,但是我没有通过思考来简化维护过程:
- 错误实现
维护到当前这个正数的总数时想当然的把所有正数的 rank 扔到了 multiset 里面,
然后用 std::distance(S.begin(), S.lower_bound(k))
来表示。
但是牛魔的,set
类容器都是不可随机访问容器啊,求迭代器距离是
而且一开始写 S.lb(k) - S.begin() 不让过编译其实已经告诉你了,但是我当时居然觉得这是对安全性要求比较严格。。。
知道了这个问题之后,要改就很轻松了。
- 改进思路
显然正数的个数是可以扔到线段树里一起维护的,然后就结束了。
然后还发现另一个唐氏指出,下面那个找第几个的完全可以推个柿子之后
佛了。
2|0权值线段树上二分
https://blog.nowcoder.net/n/90af997f26fe4e9ba18c399139d1607e
- 板子
考虑怎么优化掉二分这个 log,可以在线段树上二分。
- 先解决一个类似且简单的线段树二分问题:
对于
,求第一个 的 ,带修
显然维护一个最大值的位置线段树:不优化的做法就是二分右端点,T.rangeQuery(0, mid + 1).mx > k
但我们发现这个问题存在一个性质,先左子树后右子树这个顺序找到的第一个解一定是最早出现的。
于是有了下述思路:
每次查找时从根递归向下查找, 对于当前区间
-
若当前节点为叶子结点, 若结点的值满足
, 返回下标即可; -
若左子树最大值大于
(约束), 则左子树可能存在解, 递归查找左子树; 若左子树查找到解,则直接返回该解(这是一个重要剪枝,可以大幅优化时间, 显然此时即使右子树存在大于 的元素,也不可能是第一个出现的了,所以没必要再查,否则,若右子树最大值大于 (约束), 递归查找右子树;
- 找到权值线段树上第一个前缀和(指的是权值线段树上的前缀和,从零开始)大于 k 的权值
这个问题同于上述问题的地方是我们要找的也是第一个位置。
这个问题不同于上述问题的地方是,这个问题要求的是前缀和。前缀和这个信息显然并不属于叶子节点,所以如果这样写:
是不正确的,这实际上是在找第一个大于
要怎么维护前缀和呢?我们发现一个权值线段树上一个叶子节点的前缀和肯定是等于遍历到他之前所有叶子节点的和,也就是左子树是一定会贡献到右子树上的。
那么在操作的时候我们每次遍历左子树失败(也就是左子树的总和还不够大),准备遍历右子树时,就把左子树的贡献算上去,这样到叶子节点的时候就是对应的前缀和了。
__EOF__

本文链接:https://www.cnblogs.com/kdlyh/p/18448994.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示