算法学习笔记(42): 颜色段均摊

颜色段均摊

反正 ODT

对于 ODT 来说,其区间推平的复杂度是 O((n+m)logn) 的,十分的优秀,但是对于查询来说,我们需要通过分块或者线段进行辅助,从而达到正确的复杂度。

有一种特殊情况例外:
如果推平和查询同时发生,意味着推平时对于每一段查询的复杂度是没有问题的!

判断是否可以均摊,我们可以看是否能够构造出一个操作序列使得序列复原,如果可以复原,那么基本是不可以均摊的。

或者我们看是否能找到一个量,不增,或者不减,或者有一个神秘的上界,再抽象一点说,存在某一个势能在我们可接受复杂度内。


CF444C - DZY Loves Colors

  • 区间赋值
  • 区间权值求和

对于区间赋值来说,ODT 所谓的颜色段均摊可以很好做到 O((n+m)logn) 的复杂度。

但是我们唯一担心的是查询权值的复杂度,这是很难接受的!

所以我们需要通过线段树进行辅助:考虑到区间赋值对权值带来的影响是区间加,所以利用线段树维护即可。

乍一眼看上去是 O(nlogn+mlog2n) 的复杂度(加上了修改时线段树的复杂度),但是考虑到实际上,每新增或者减少一个颜色段,只会在线段树上区间加一次,也就是说 O(n+m) 个颜色段带来的是 O((n+m)logn) 的线段树操作,所以仍然是一个 logn 的。

提交记录:https://codeforces.com/problemset/submission/444/233908238


CF453E - Little Pony and Lord Tirek

这下操作可能困难了。

这道题其实就是所谓的特殊情况:

如果推平和查询同时发生,意味着推平时对于每一段查询的复杂度是没有问题的!

也就是说,我们在区间推平的时候顺便维护一下这一段的答案即可。

现在的问题转化为经过 t 时刻后,[l,r] 的权值和。

如果没有对于 mimin 是简单的,我们需要想办法绕开它。

考虑权值关于时间的函数实际上是分段的:

fi(t)={0,ri=0ri×t,tmirimi,otherwise

考虑到 miri105,所以可以据此建立可持久化线段树,查询区间即可。

注意由于我们维护的是一次函数,所以需要 K,B 两棵线段树。

提交记录:https://codeforces.com/contest/453/submission/233920307


P5066 [Ynoi2014] 人人本着正义之名

很套路的是将连续的 01 段缩成一段,但是呢?

考虑到每次操作,可能造成如下的影响:

  • 一些 0 段长度 ±1
  • 一些 1 段长度 ±1

考虑到区间长度在变化,我们可以通过平衡树维护,例如 wblt

但是我们会发现存在一个段长度变为 0 的情况,此时这个区间应当被删除,不再使用。

所以我们需要快速的找到是否需要删除某个区间,这容易利用在平衡树上维护两者的最短长度实现。如果发现了变为 0 的段,在线段树上二分下去删除它即可。

考虑这样的段一共有 O(n) 段,每次删除代价是 O(logn) 的,总复杂度是 O(nlogn),可以接受。

每次操作也是 O(logn) 的,总复杂度便是 O(nlogn+mlogn),十分优秀。

posted @   jeefy  阅读(301)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示