1 条题解

  • 0
    @ 2025-10-27 17:16:44

    问题抽象

    我们有一个连通无向图,NN 个节点,MM 条边,每条边 ii 有宽度 WiW_i

    对于每个查询 XjX_j,我们需要选择一些边构成生成树,使得整张图连通,并且最小化总代价:

    e生成树WeXj\sum_{e \in \text{生成树}} |W_e - X_j|

    其中我们可以任意调整边的宽度(每调整 11 花费 11),但宽度不能低于 11


    关键观察

    1. 问题转化

    实际上,我们不需要真的"调整所有边的宽度",而是选择一组边构成生成树,使得这些边宽度与 XjX_j 的绝对差之和最小。

    因为对于不在生成树中的边,我们可以不管它们(不花费代价),只需要保证生成树中的边连通全图即可。

    2. 按边权排序

    将边按宽度 WiW_i 排序。对于固定的 XX,考虑每条边的代价函数 fe(X)=WeXf_e(X) = |W_e - X|

    这是一个分段线性函数:当 XWeX \le W_e 时,代价为 WeXW_e - X;当 XWeX \ge W_e 时,代价为 XWeX - W_e

    3. 生成树的结构

    对于固定的 XX,我们想要选择生成树使得 WeX\sum |W_e - X| 最小。

    这等价于:我们偏好选择宽度接近 XX 的边。

    实际上,最优生成树可以通过以下方式获得:

    • 将边按 WeX|W_e - X| 排序
    • 用 Kruskal 算法选择前 N1N-1 条边(按这个排序)

    但直接对每个 XjX_j 做一次 Kruskal 是 O(QMlogM)O(QM \log M),不可行。


    核心解法

    1. 区间划分

    注意到当 XX 变化时,边的相对顺序只在某些关键点发生变化。这些关键点就是所有 (Wi+Wj)/2(W_i + W_j)/2(其中 iji \ne j)。

    实际上,我们只需要考虑所有 WiW_i 以及它们的中点,因为 WeX|W_e - X| 的排序只在 XX 跨越这些点时改变。

    2. 双序列维护

    将边按 WiW_i 排序得到序列 w1w2wMw_1 \le w_2 \le \cdots \le w_M

    对于给定的 XX,代价函数 wiX|w_i - X|iki \le k 时是递减的(XwiX - w_i),在 i>ki > k 时是递增的(wiXw_i - X),其中 kk 是满足 wkXw_k \le X 的最大下标。

    因此,按 wiX|w_i - X| 排序等价于:

    • w1,,wkw_1, \dots, w_k 按降序排列(因为 XwiX - w_iii 增大而减小)
    • wk+1,,wMw_{k+1}, \dots, w_M 按升序排列
    • 然后归并这两个序列

    3. 生成树选择的单调性

    关键结论:存在一个下标 p(X)p(X),使得最优生成树由:

    • 最小的 rr 条边(按原 WiW_i 排序)中的某些边
    • 和最大的 ss 条边中的某些边组成 其中 r+s=N1r + s = N-1

    更精确地,最优生成树会选择最接近 XXN1N-1 条边(按 WiX|W_i - X| 排序)。

    4. 预处理所有关键区间

    由于 N500N \le 500,但 MM 可能很大,QQ 非常大,我们需要高效处理。

    解法思路:

    1. 将数轴按所有 WiW_i(Wi+Wj)/2(W_i + W_j)/2 分成 O(M2)O(M^2) 个区间
    2. 在每个区间内,最优生成树的边集不变(按 WeX|W_e - X| 的排序不变)
    3. 对每个区间,计算生成树代价关于 XX 的线性函数
    4. 对于查询 XjX_j,找到所在区间,用对应的线性函数计算答案

    由于 M105M \le 10^5O(M2)O(M^2) 太大,需要优化。实际上,只需要考虑 O(MN)O(MN) 个关键点,因为生成树最多 N1N-1 条边。


    算法框架

    1. 排序边:将边按 WiW_i 排序
    2. 生成关键点:考虑所有 WiW_i 以及它们的中点,但只保留可能改变生成树组成的点
    3. 区间处理:对每个区间 [L,R][L,R],确定最优生成树的边集,并计算代价函数 cost(X)=eTWeXcost(X) = \sum_{e \in T} |W_e - X|
    4. 查询处理:对每个 XjX_j,二分找到所在区间,用对应的线性函数计算答案

    复杂度优化

    • 关键点数量:O(MN)O(MN)
    • 每个区间用 Kruskal 求生成树:O(MlogM)O(M \log M)
    • 总预处理:O(M2NlogM)O(M^2N \log M) 仍然太大

    实际高效做法:

    • 利用最优生成树在 XX 变化时的单调性
    • 使用双指针维护当前最优生成树
    • 预处理所有"边交换"事件,当 XX 变化时只需 O(1)O(1) 更新生成树

    总结

    这道题的核心是:

    1. 问题转化:将重构问题转化为生成树选择问题
    2. 代价函数分析WeX|W_e - X| 是分段线性函数
    3. 区间划分:最优生成树在 XX 的某些区间内保持不变
    4. 高效查询:预处理线性函数,支持快速查询

    这是一道结合了生成树理论参数化优化分段函数分析的高难度题目,需要深入理解图论性质和函数性质才能设计出高效算法。

    • 1