(树上)启发式合并
启发式,就是发扬人类智慧来优化一些算法,比如启发式搜索和启发式合并。
启发式搜索就是根据人类直觉,给搜索设定一个估价函数,估价函数更符合条件的优先处理。举个例子,最短路里的估价函数就是最短距离。因为你手模的时候知道要先找最近的路而不是把所有的路都模拟一遍,把这个过程放到程序里实现就是启发式搜索。
然后是启发式合并。这个也很直觉,合并两个东西的时候把小的合并到大的里可以减小复杂度。而且这个看起来很暴力的东西可以把
具体证明一下:现在你有
操作很简单,把小的部分的所有元素暴力插入大的部分里就行了。比如并查集,每个集合记录一个
注意:splay的启发式合并复杂度是
补充:据jijidawang说Splay不管什么顺序合并都是一个
然后是今天的主题:dsu on tree,即树上启发式合并。大体的思想差不太多,就是将小的子树的信息合并到大的子树上。复杂度证明类似上面的,同样是
上个例题:P4577 领导集团问题(如果您觉得这个就是个普通的启发式合并,和dsu on tree没什么关系的话,那是您说的对)
题意:树上LIS。就是树上求所有从根到叶子的链的LIS中最大的。
首先我们原先
for(int i=1;i<=n;i++){
if(a[i]>=ans[ans[0]])ans[++ans[0]]=a[i];
else{
int x=lower_bound(ans+1,ans+ans[0]+1,a[i])-ans;
ans[x]=a[i];
}
}
这个原理不再叙述,忘记的请出门左转模板。
我们可以把这个数组扔到树上。具体地,我们每次遍历完当前节点的所有子树之后,所有子树的元素构成了
- 动态开点线段树合并,由于每个节点要更新一次,还要合并所有节点,所以复杂度是
的。当然线段树合并的常数要多大有多大。于是我们有另一种多一个 但是跑的更快的做法。 - 由于这个
数组是有序的,所以对每个节点开一个multiset维护,合并的时候暴力将子树的所有元素插入当前节点。当然这样把所有的都插入一次显然是 的。我们使用启发式合并,将所有其他子树中的multiset中的元素插入最大的子树,这样就能保证复杂度是 的。
然后是另一个例题:给出一棵
这个直接统计每个子树中出现颜色然后合并就行了。具体地说,我们首先扫一遍所有的轻儿子计算答案,但是不在颜色数组内保存。然后搜重儿子并将颜色记录进数组。最后扫一遍所有的轻儿子合并答案,复杂度
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?