虚树 Virtual Tree

更新日志 2025/01/07:开工。

概念

在很多树上问题中,我们会发现,实际需要的,只有几个关键点。

那么我们就可以针对这些关键点进行操作。更具体地,建一棵规模更小的,但是仍能完成要求的浓缩过的树,即为虚树

思路

简介

首先,常识可得:除了关键点,关键点两两的 \(\text{LCA}\) 也需要储存重要信息。

所以建立虚树的关键问题就是:找 \(\text{LCA}\)、按原关系建树。

下面介绍两种构造方案。

二次排序

\(O(m\log n)\)\(m\) 为关键点数。

大概过程就是:

  • 关键点按 \(\text{DFS}\) 序排序。
  • 相邻两点求出 \(\text{LCA}\),加入序列。完成后去重,序列中的节点就是虚树中的节点了。
  • 对于每两个相邻点 \(x,y\),连接 \(\mathrm{LCA}(x,y)\)\(y\)

下面证明第二和第三过程。

首先,可以想象,按 \(DFS\) 序排序后,相邻的节点要么是祖先关系、要么是兄弟关系(很废话),且从左向右排开。假如二者跨了子树——总会有这样的点——就会把两棵子树的父节点加入,而它也是任意左子树点和任意右子树点的 \(LCA\)。感性理解即可。

然后,我们分讨一下第三过程:

  • \(x,y\) 为祖先关系,那么直接连边显然无问题,且二者之间没有别的关键点了。
  • \(x,y\) 非祖先关系,\(\text{LCA}(x,y)\) 显然也应该是 \(y\) 的祖先。且二者之间显然也没有别的关键点了,因为 \(x,y\)\(\text{DFS}\) 序上相邻。可以大概想象一下。
  • 发现第一个点没有连边,但是作为 \(\text{DFS}\) 序最小的,它必然是根节点,所以无需主动连边。

证毕。不难发现虚点个数为实点个数两倍。

单调栈

类似于笛卡尔树之类的,我们考虑维护虚树上的一条链。

首先,我们把原根节点加入进去,确保正确性。

我们考虑加入一个节点的情况:

  • 若栈顶节点是新加入节点的祖先,直接入栈。
  • 否则:
    • 若栈顶元素 \(\text{DFS}\) 序大于 \(\text{LCA}\),说明它是当前节点的一个兄弟节点:
      • 若次大元素仍大于 \(\text{LCA}\),将栈顶元素与次大元素连边,弹出。
      • 否则,说明当前栈顶元素的父节点应为 \(\text{LCA}\),连边,弹出。
    • 若栈顶元素 \(\text{DFS}\) 序小于 \(\text{LCA}\),说明此时 \(\text{LCA}\) 还没入栈,将其加入后,再把当前节点加入即可。

最后剩下的链里的节点依次连边,虚树就构建好了。

posted @   LastKismet  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示