【笔记】启发式合并
启发式合并用于解决这样一类问题
给定个集合,每个集合开始只有个数,你需要支持每次合并两个集合
直接做显然是的,但我们可以稍加优化。
每次合并,我们都选择较小的一个集合,将它合并到较大的集合上。
看上去本质上没有改变,但时间复杂度直接由 降低至 。
为什么复杂度是 的,因为对于每个元素,每次合并一定是从小的集合合并到大的集合,所以合并后的集合大小一定翻倍,那么一个元素最多移动 次,总的时间复杂度为 。
简述:给定 个初始有 个元素的栈,每次支持将一个栈合并到另一个栈(按栈的出入顺序)。
直接模拟不难做到的复杂度。
观察一下发现这就是启发式合并的模型,考虑用启发式合并解决。
我们用双端队列模拟一个栈,开始队首对应栈顶。
启发式合并时,发现栈 得到的栈正好是 得到的栈的反序,所以我们对双端队列记录一个表示队列里的元素是否反转。
简述:支持连边操作和路径第小操作,强制在线。
如果不强制在线我们可以将最终的树建出来,然后直接可持久化线段树。
如果强制在线,我们可以考虑动态建树,但由于连边后根会移动,所以我们需要对整棵树重新构建。
但观察一下可以发现,我们合并两棵树时,有一棵树可以不用改变,所以合并时我们直接暴力重构较小的树,时空复杂度为 。
不难发现对于一条直上直下的单链,有多少点就要划分多少段。
所以划分段数就是子树深度,我们用堆维护这些分段,然后启发式合并即可。
时间复杂度。
简述:支持合并联通块和查询联通块第小。
用平衡树维护联通块中所以值,然后直接启发式合并即可。
简述:可持久化并查集
由于可持久化后不便于路径压缩,所以考虑启发式合并。并查集按深度启发式合并,同样可以得到的时间复杂度。
用可持久化线段树实现可持久化数组,然后时限并查集,时间复杂度。
树上启发式合并,简称 DSU on Tree
。
解决一类静态子树问题,我们按照以下顺序。
- 计算所有轻儿子贡献,并删除贡献
- 计算重儿子贡献,保留贡献
- 将轻儿子贡献合并到重儿子中
- 回答当前子树询问,回溯
不难发现一个节点会在重儿子的子树中总共计算一次,在每个轻儿子的子树中计算次,但一个节点到根的作为轻儿子的次数不超过,所以时间复杂度为。
模板题,类似莫队开一个桶记录每种颜色出现次数,然后套用上面的套路即可。
需要一些技巧的 DSU ,由于要统计所有路径,我们可以类似点分治先递归计算所有子树中路劲的最大值,再计算以当前点为 LCA 的路径。
计算当前点的路径,我们开一个桶记录路径异或值为的所有路径中,能够达到的最大深度是多少。然后在合并子树时统计答案即可。
我们仍然按照套路合并子树,这样时间复杂度是。
作者:7KByte
出处:https://www.cnblogs.com/7KByte/p/16143270.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?