区间/树链染色问题

给定一个 n 个数的序列,m 个操作:每次对一个区间进行染色,其中染过的位置不用再染。

其中 n106,m106

暴力模拟的时间复杂度是 O(nm) ,显然不能接受。考虑这个暴力慢在哪里?

暴力算法每次都要遍历一遍区间,由于染过的地方不能再染,所以暴力在已经染过的地方花费了大量时间,有没有办法排除这些 冗余 呢?

我们可以用并查集

fx 表示位置 x 自己及其后面第一个没有染色的地方,假设 x 这个位置被染色了,就将 fx=fx+1。在区间染色时,只需将循环这么写即可。

for(int i = l; i <= r; i = f[i]) {//在区间[l,r]染色
...
}

经过这样处理,每次跳到的位置都是没有染色的地方,于是不管 m 有多大,最多只会染色 n106 次,于是时间复杂度就被降低到了 O(n).

原题:白雪皑皑

这类题目还有一种变式:

n 个数,每次对 [l,r] 区间进行染色操作,可以覆盖掉已经染色的区域,问最后数列长什么样?

照题目来看,如果区间 [l,r] 被染了蓝色,再在区间 [l,r] 上染红色,最后这个区间应该是红色的,假如我们将这个过程倒过来:在 [l,r] 上染红色后,再染蓝色就是无效的,和上一题 “染过的地方不能重复染” 有点像,推广到一般情况也没有问题。所以只需将整个过程倒过来就和上一题一模一样了。

上述是序列上的情况,接下来讨论树链上的情况。


其实是大同小异的,我们只需记录每个节点的父亲,再将深度大的向上跳,剩下的就和序列上的一模一样了。

例题:数列

经过一些简单的转化就变成对树链上的每一条边赋值(已经赋过的不用赋),由于是边比较特殊,设 fx 表示从 x 向上跳,最远可以跳到的点,即中间的边全部经过赋值。每次对一个点赋值后,将 fx=find(fax) 即可。


来总结一下这种问题的指导思想:

  • 排除冗余:由于染过的地方没有必要再染,所以使用并查集跳过大大优化了时间复杂度。
  • 与倍增的联系:一般来说,一个个跳导致超时,要么考虑倍增,要么考虑并查集,其中倍增可以处理静态的问题,这和 dsuontree 有点像;但是并查集可以处理动态问题
posted @   2017BeiJiang  阅读(48)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示