加载中...

2025南昌邀请赛L (换根区间lca)

L. Regnaissance

很不错的一道缝合怪题目,将 换根求两点 lca 与 区间 lca 结合在了一起,导致在各种经典结论加持的情况下需要使用复杂数据结构维护信息。

具体实现使用了 主席树 + ST表维护区间LCA + 树上倍增,并需要结合一些经典结论。

首先记录一下 多查询换根求任意两点 lca 的结论:假设以 1 为根节点,预处理出了根固定为 1 时的树形结构的相关信息。假设现在需要处理根节点为 \(rt\)、查询 LCA(\(x,y\)) 的情况:

  • 观察换根前后树结构的变化:可以发现只有在原树中 \(rt\) 的所有祖先结点之间的祖先关系完全倒转过来了,其他结点均无变化。
  • 接下来分 3 种情况讨论:
    • \(x, y\) 均在 \(rt\) 子树内:显然答案为 LCA(\(x,y\));
    • \(x, y\) 其中一点在 \(rt\) 子树内,另一点在 \(rt\) 子树外:显然答案为 \(rt\)
    • \(x, y\) 均在 \(rt\) 子树外:手玩几种情况就能发现,当 LCA(\(x,y\)) 是 \(rt\) 的祖先时,答案为 LCA\((rt, x)\) 与 LCA\((rt, y)\) 中深度较深的那一个;否则答案就是 LCA\((x, y)\)

而 区间 lca 是一个静态 RMQ 问题,且求 lca 与 max/min 一样满足可重复性,因此可以使用 ST 表维护。或者还可以利用一个结论:一个点集内所有点的 lca,等于该点集内 \(dfn\) 序最小 与 \(dfn\) 序最大的两个点的 lca。 于是用 ST 表维护 \(dfn\) 序的最值也可以做。

而本题需要解决 多查询换根求任意编号区间在 \([l,r]\) 内的所有点的 lca 这个问题。利用上述结论进行分析:

  • \([l,r]\) 内所有点均在 \(rt\) 子树内,则答案显然为 LCA(\([l\backsim r]\));
  • \([l,r]\) 存在部分点在 \(rt\) 子树内,部分点在 \(rt\) 子树外,则答案显然为 \(rt\)
  • \([l,r]\) 内所有点均在 \(rt\) 子树外:与两个点的情况类似:当 LCA(\([l\backsim r]\)) 是 \(rt\) 的祖先时,答案为 LCA\((rt, l)\) 、 LCA\((rt, l+1)\) ...、LCA\((rt, r)\) 中深度最深的那一个,也就是在 \(rt\) 的所有祖先结点中,包含了编号在 \([l, r]\) 内的某些点的最深祖先;否则答案就是 LCA\([l\backsim r]\)

由上述分析,产生了几个不是很容易想的问题:

  • 如何知道 编号在 \([l,r]\) 内的点子树 \(rt\) 之间的包含关系(全部包含/部分包含/不包含): 注意到这两个点集一个是编号连续,一个是 \(dfn\) 序连续(设为 \([L, R]\))。将问题都转化到 \(dfn\) 序上,问题就变成了:查询编号在 \([l, r]\) 内的点中,\(dfn\) 序在 \([L, R]\) 内的点的数量。 以编号为时序建立主席树,维护 \(dfn\) 序的桶,查询相应版本的线段树就行了。
  • 当 LCA(\([l\backsim r]\)) 是 \(rt\) 的祖先时,如何快速找到 LCA\((rt, l)\) 、 LCA\((rt, l+1)\) ...、LCA\((rt, r)\) 中深度最深的那一个:即在 \(rt\) 的所有祖先结点中,包含了编号在 \([l, r]\) 内的某些点的最深祖先。以深度为序考虑 \(rt\) 的所有祖先,显然这是具有二段性的,可以利用树上倍增快速找到这个结点,check 仍然利用 主席树 + dfn序 解决。

总复杂度为 \(O(n\log^{2} n + q \log^{2}n)\),瓶颈在预处理 ST 表(因为预处理的是 LCA,需要多一个 \(\log\)) 与 第二个问题的树上倍增套主席树查询。

code

posted @ 2026-05-19 22:35  小橘奏  阅读(19)  评论(0)    收藏  举报