SN省集 Day2 T1

双城通路题解

下面默认祖先关系包含结点自身。

记:

  • \(Sub_S(u)\) 表示在 \(S\) 树中以 \(u\) 为根的子树点集;
  • \(Sub_T(u)\) 表示在 \(T\) 树中以 \(u\) 为根的子树点集;
  • \(u\)\(v\) 在某棵树中的祖先,等价于 \(v\) 在这棵树中属于 \(u\) 的子树。

路线贡献

记两棵树中从根到点的距离分别为 \(d_S(u)\)\(d_T(u)\)

若一条跨城隧道位于编号 \(p\) 处,长度为 \(r\),那么它能被从 \(S\)\(x\)\(T\)\(y\) 的路线使用,当且仅当:

  • \(p\)\(x\)\(S\) 树上的祖先;
  • \(p\)\(y\)\(T\) 树上的祖先。

此时这条路线长度为

\[d_S(x)-d_S(p)+r+d_T(y)-d_T(p) \]

把所有位于同一个编号 \(p\) 的隧道合并。设这些隧道长度分别为

\[r_1,r_2,\ldots,r_{cnt_p} \]

并记

\[cnt_p=\text{编号 }p\text{ 处的隧道条数} \]

\[sum_p=\sum_{i=1}^{cnt_p} r_i \]

并定义

\[base_p=sum_p-cnt_p(d_S(p)+d_T(p)) \]

若编号 \(p\) 处的隧道能被 \((x,y)\) 使用,那么每一条这样的隧道都会产生一条不同路线,它们的长度之和为

\[\sum_{i=1}^{cnt_p}\left(d_S(x)-d_S(p)+r_i+d_T(y)-d_T(p)\right) \]

把与 \(i\) 无关的项提出,得到

\[cnt_p(d_S(x)+d_T(y)-d_S(p)-d_T(p))+sum_p \]

整理后就是

\[cnt_p(d_S(x)+d_T(y))+base_p \]

这就是编号 \(p\) 处所有隧道对 \((x,y)\) 的总贡献。若 \(p\) 不是 \(x\)\(S\) 中的祖先,或不是 \(y\)\(T\) 中的祖先,则这些隧道对 \((x,y)\) 的贡献为 \(0\)

固定共同结点

考虑一个编号 \(t\)。计算 \(val_t\) 时,可以理解为暂时假定 \(t\) 之下的所有点之间都没有跨城隧道,只统计 \(t\) 及其祖先处的隧道贡献。

\[C_t=\sum_{p:\ p\text{ 同时是 }t\text{ 在 }S,T\text{ 中的祖先}} cnt_p, \]

\[B_t=\sum_{p:\ p\text{ 同时是 }t\text{ 在 }S,T\text{ 中的祖先}} base_p \]

再令

\[mxS_t=\max_{u\in Sub_S(t)} d_S(u), \]

\[mxT_t=\max_{u\in Sub_T(t)} d_T(u) \]

此时我们只需要考虑

\[x\in Sub_S(t),\quad y\in Sub_T(t) \]

在这种前提下,来自 \(t\) 及其共同祖先这些隧道的贡献中,\(C_t\)\(B_t\) 已经固定,只剩下 \(d_S(x)+d_T(y)\) 需要最大化。由于边权均为正数,显然应分别在 \(S\)\(t\) 子树和 \(T\)\(t\) 子树中取根距最大的点。因此定义

\[val_t=C_t(mxS_t+mxT_t)+B_t \]

现在考虑如何处理询问。对于询问编号 \(s\),要求 \(x\in Sub_S(s)\)\(y\in Sub_T(s)\)。如果某个编号 \(t\) 要对这个询问产生贡献,那么以 \(t\) 为根继续向下选出的 \(x,y\) 也必须仍然落在 \(s\) 的两个子树中,因此 \(t\) 必须满足

\[t\in Sub_S(s)\cap Sub_T(s) \]

反过来,只要 \(t\in Sub_S(s)\cap Sub_T(s)\),那么 \(Sub_S(t)\subseteq Sub_S(s)\)\(Sub_T(t)\subseteq Sub_T(s)\),由 \(val_t\) 选出的最优 \(x,y\) 一定是询问 \(s\) 的合法选择。因此最终答案就是这个子树交中的最大点权:

\[ans_s=\max_{t\in Sub_S(s)\cap Sub_T(s)} val_t \]

于是问题被转化为一个二维矩形最大值问题。令 \(dfns,outs\) 表示 \(S\) 树的 DFS 序区间,\(dfnt,outt\) 表示 \(T\) 树的 DFS 序区间。对每个编号 \(t\) 建一个点:

  • 第一维坐标为 \(dfns(t)\)
  • 第二维坐标为 \(dfnt(t)\)
  • 点权为 \(val_t\)

也就是二维平面上的点

\[(dfns(t),dfnt(t)), \]

对每个 \(s\),需要查询矩形

\[[dfns(s),outs(s)]\times[dfnt(s),outt(s)] \]

内的最大点权。

计算点权

先分别 DFS 两棵树,得到:

  • \(dfn_S,out_S\)\(dfn_T,out_T\)
  • 根到点距离 \(d_S,d_T\)
  • 子树内最大根距 \(mxS,mxT\)

然后在 \(S\) 树上 DFS,维护当前 \(S\) 根到当前点路径上的活跃结点。

进入结点 \(u\) 时,若某个点 \(x\)\(T\) 树中位于 \(u\) 的子树内,则 \(u\) 也是 \(x\)\(T\) 树上的祖先。因此把 \(u\) 的贡献加到 \(T\) 树 DFS 序区间:

\[[dfn_T(u),out_T(u)] \]

用两个支持“区间加、单点查”的树状数组,分别维护 \(cnt_u\)\(base_u\)。访问到当前结点 \(u\) 时,在位置 \(dfn_T(u)\) 查询,就能得到 \(C_u\)\(B_u\)

于是可以算出

\[val_u=C_u(mxS_u+mxT_u)+B_u \]

DFS 离开 \(u\) 时撤销它的区间贡献即可。

矩形最大值

现在要对每个 \(s\) 求二维矩形内最大点权。

当前实现使用线段树分治处理第一维 \(dfn_S\)

  • 对每个询问 \(s\),它在第一维上的区间为 \([dfn_S(s),out_S(s)]\)
  • 把这个区间挂到线段树上某个跨过中点的结点,递归处理;
  • 在处理线段树结点 \([l,r]\) 时,中点为 \(mid\)
  • \(mid\) 向左扫描,把对应点按 \(dfn_T\) 插入一棵维护最大值的线段树;
  • 处理左端点等于当前扫描位置的询问;
  • 再从 \(mid+1\) 向右扫描,类似处理右端点等于当前扫描位置的询问。

对每个询问 \(s\),第二维只需要在线段树中查询

\[[dfn_T(s),out_T(s)] \]

上的最大值,并更新 \(ans_s\)

每个点和每个询问在分治线段树中只会参与 \(O(\log n)\) 次,因此这一部分复杂度为

\[O(n\log^2 n) \]

也可以使用二维线段树、归并树等静态二维矩形最大值结构完成。

复杂度

合并隧道和两棵树 DFS 的复杂度为

\[O(n+m) \]

计算所有 \(val_t\) 的复杂度为

\[O(n\log n) \]

处理所有矩形最大值询问的复杂度为

\[O(n\log^2 n) \]

总时间复杂度为

\[O(n\log^2 n+m) \]

空间复杂度为

\[O(n\log n) \]

或按实现方式为线性到 \(O(n\log n)\) 级别。

注意答案可能很大,所有距离、贡献和答案都需要使用 long long

posted @ 2026-07-03 18:50  wjx_2010  阅读(12)  评论(0)    收藏  举报