【图论】树上启发式合并 学习笔记
DSU on Tree
启发式算法
启发式算法是基于人类的经验和直观感觉(),对一些算法的优化。
比如并查集的启发式合并,每次把小的集合合并到大的,这样复杂度显然优于把大的合并到小的。
再经过严谨证明,许多诸如此类的优化可以把时间复杂度降低层级。
树上启发式合并
先看下面这道例题:
CF600E Lomsat gelral
题意:求出一棵有根树每颗子树所有出现最多颜色其编号的和。
先考虑暴力做法:对于每一颗子树,暴力数出其各颜色出现次数。时间复杂度 \(O(n^2)\)。
考虑对子树对父节点的影响:在上述暴力过程中,子树的颜色可以直接合并到父节点上,所以就有下面两种做法:
- 树链剖分。对原树进行重链剖分,直觉上,每次保留重子节点的信息,重新计算其他轻节点的信息可以优化时间复杂度;事实上,由重链剖分的结论可知,任意节点走到根节点最多经过 \(O(\log n)\) 条轻边。所以总的时间复杂度为 \(O(n \log n)\)。
- 按集合大小启发式合并。对于每个节点,用一个
map
存储其子树内信息。通过深度优先搜索合并集合(深度大的子树计算完后信息就无用了,若集合大可以swap
到父节点)。每次合并集合大小会翻倍,所以合并插入的次数是 \(O(n \log n)\),总的时间复杂度是 \(O(n \log ^ 2 n)\)。
上面两种做法的代码实现:这里。