[Ynoi2016] 镜中的昆虫 题解

[Ynoi2016] 镜中的昆虫 题解

好题值得一做。

题目大意:给一个序列,有若干个离线询问,每次可以区间推平或询问区间内的颜色个数,数据范围是 \(10^5\) 级别。

解题思路:我们可以先考虑一个弱化版,每次是单点修改怎么做,类似于 CF848C

我们考虑维护出每一个位置上一个与它相等的位置是 \(pre_i\),那么区间内数颜色就是求二维偏序 \(l\le i\le r\land pre_i<l\)

我们又发现,每次单点修改只会有 \(O(1)\) 个位置的 \(pre\) 被修改,可以对每个颜色开一个 set 方便维护每次 \(pre\) 的变化。

之后我们就把修改和查询都离线下来,这样多了时间一维的限制,跑 cdq分治 即可,复杂度 \(O(n\log ^2n)\)

考虑完弱化版,本题怎么做呢?可以发现即使是区间推平,\(pre\) 数组的总变化量是均摊 \(O(n+m)\) 的。

证明也很容易想,考虑到新推平的区间覆盖了原来的若干个区间,那么只有原来若干个区间的左端点的 \(pre\) 会改变,而区间的其他位置 \(i\) 由于与前面的颜色仍然相同,保持 \(pre_i=i-1\) 不变。而每个区间只会被覆盖一次,一共只有 \(O(n+m)\) 个区间。

当然还有这些被覆盖区间的相同颜色后继区间的左端点会被改变。以及 \(L,R+1\) 也可能改变。但总的还是 \(O(n+m)\)

实现方面,不仅对每种颜色开一个 set,里面存放这种颜色的每个区间,这样可以方便维护出贡献。还要对所有区间开一个 set,同时存放颜色,这样可以方便地删除区间。

而且我们不要一边删除区间一边算贡献,先把所有可能会改变的点存起来,把它们的贡献去掉,之后修改 set 至当前状态,再把这些点的贡献加上。

对于 cdq分治 部分,不要把询问与修改放在同一个容器里,可以分治时间,把左半时间的修改和右半时间的询问分别放进 vector 里,然后分别排序,然后用双指针扫两个 vector。是不是很类似整体二分的写法呢?

最后 \(pre\) 的变化量是 \(O(n)\) 级别的,用 set 处理是 \(O(n\log n)\),分治部分是 \(O(n\log ^2n)\)。总复杂度为 \(O(n\log ^2n)\)

posted @   dengchengyu  阅读(8)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示