Loading

学习笔记 【启发式合并】

启发式合并

前言

启发式合并十分得神奇,如果不刻意去想可能几乎想不到这种优化方法,但是在某些时刻看似是暴力的代码套上这几个字再加上证明复杂度,就能缩一圈,但没有模板,代码因题而异,十分灵活。

概念简述

  • 对于 \(n\) 个初始大小为1的可重集,每次选择(被动)两个集合合并时,每次将 \(S_1\)\(S_2\) 合并的代价是其中一个集合的大小,而目的时合并成 \(1\) 个可重集的最小代价。

    每次合并,很显然的一种贪心方法是将较小的集合合并到较大的集合,复杂度为 \(O(\min(S_1,S_2))\) ,而最后的时间复杂度的阶也很神奇,是 \(O(n\log_2n)\)

证明

观察每次合并操作将较小的集合合并到较大的集合,而每个元素只有在较小的集合才会产生贡献,但每次合并操作对于较小的集合都会扩大一倍,而对于刚开始的大小为 \(1\) 的集合,最多会带此元素作为较小的集合扩大 \(\lfloor\log_2n\rfloor\) 次,而每个元素扩大 \(\lfloor\log_2n\rfloor\) 次后复杂度为 \(O(n\log_2n)\) ,对于随机数据完全达不到这个上限,我们还是保守的将其估计为此。

例题

(持续更新ing)

  • \(\large\texttt{LG U41492}\)

    树上启发式合并模板题。

    将问题转换到了树上,其实就是规定了每次操作合并的两个可重集。

    在 DFS 遍历到某个节点的时候保留一颗最大的子树的答案,再将其它兄弟子树所有节点后合并到那颗最大的子树的答案中,得到父亲节点的答案。

    在一个节点中,每次对于要合并的子树大小最少扩大一倍,而对于某个节点,它在较小的子树中合并产生贡献为包括它的所有子树的合并次数,而这个合并次数不超过 \(\log_2n\) ,因此合并次数也是不超过 \(O(n\log_2n)\) (对于随机数据十分得松)。

posted @ 2021-03-11 15:43  RedreamMer  阅读(111)  评论(0编辑  收藏  举报