1 条题解

  • 0
    @ 2025-12-1 16:12:15

    好的,这是该题目的详细文字题解。


    NOI 2014《购票》题解

    问题抽象

    我们有一棵以 11 为根、nn 个节点的树,每个节点 vv(除根外)有:

    • 父亲 fvf_v
    • 到父亲的距离 svs_v
    • 票价参数 pv,qvp_v, q_v
    • 距离限制 lvl_v

    vv11 可以分段购票:每次选择 vv 的一个祖先 aa,花费 pvdist(v,a)+qvp_v \cdot \text{dist}(v,a) + q_v,但要求 dist(v,a)lv\text{dist}(v,a) \le l_v。求每个 vv11 的最小总花费。


    1. 基础定义与 DP 方程

    dud_u 表示 uu 到根 11 的距离(边权和,前缀和),可以通过一次 DFS 求出。

    dpudp_u 表示从 uu11 的最小总花费。对于 u1u \neq 1

    $$dp_u = \min_{a \in \text{anc}(u),\ d_u - d_a \le l_u} \big\{ dp_a + (d_u - d_a) \cdot p_u + q_u \big\} $$

    其中 anc(u)\text{anc}(u)uu 的祖先集合(含 uu 自身)。


    2. 公式变形

    把常数部分分离:

    $$dp_u = \min_{a} \big\{ (dp_a - d_a \cdot p_u) \big\} + d_u \cdot p_u + q_u $$

    对于固定的 uu,我们要在满足 dadulud_a \ge d_u - l_u 的祖先 aa 中,最小化:

    F(a)=dpadapuF(a) = dp_a - d_a \cdot p_u

    xa=dax_a = d_aya=dpay_a = dp_a,那么 F(a)=yapuxaF(a) = y_a - p_u \cdot x_a
    这是一个关于 pup_u线性函数形式:在二维平面上有若干点 (xa,ya)(x_a, y_a),要找一条斜率 k=puk = p_u 的直线 y=kx+by = kx + b 穿过某点时的截距 bb 最小,即 b=yakxab = y_a - kx_a 最小。


    3. 几何转化:凸壳维护

    在平面上,如果我们有一组点 (xi,yi)(x_i, y_i),那么使 yikxiy_i - kx_i 最小的点,一定在这些点构成的下凸壳上。

    下凸壳性质:按 xx 排序后,相邻点连线斜率递增。

    查询:给定斜率 kk,在下凸壳上找到第一个斜率大于 kk 的线段左端点,该点即为最优决策点(可二分查找)。


    4. 距离限制的处理

    对于 uu,合法的 aa 需满足 dadulud_a \ge d_u - l_u
    因为 dad_aaa 靠近根而减小,所以这相当于在祖先链上取一个后缀。

    因此我们需要在 uu 到根的路径上,对 dad_a 在某个值以上的祖先点维护凸壳,并支持查询。


    5. 特殊情况分析

    题中 tt 参数提示了部分分做法:

    • t=0t=011lvl_v 极大,无距离限制。此时只需在整条祖先链的凸壳上查询。因为 fv=v1f_v = v-1(链)或任意树但无限制,可以用栈维护凸壳,O(nlogn)O(n \log n)O(n)O(n)(若 pp 单调)解决。

    • t=0t=022:树是一条链,fv=v1f_v = v-1。祖先链就是 1,2,,u1,2,\dots,u。此时 dd 单调递增,可以用单调队列维护凸壳,并在队列上二分找到第一个 dadulud_a \ge d_u - l_u 的位置(即满足距离限制的最远祖先),然后在该段凸壳中二分查询。复杂度 O(nlogn)O(n \log n)

    • t=3t=3:一般情况,树形态任意,有距离限制。


    6. 一般情况解法:树分治

    对于树上任意路径问题,点分治是常用方法。

    核心思想
    考虑当前分治中心 rtrt,对于 rtrt 子树中的节点 uu,它的路径可以分为两段:urtu \to rtrt1rt \to 1
    如果我们在 rtrt 处购票,则可以从 rtrt 跳到某个祖先 aa,这样 uu 的花费为 dpa+(duda)pu+qudp_a + (d_u - d_a) \cdot p_u + q_u,其中 dudalud_u - d_a \le l_u


    分治步骤

    1. 找重心 rtrt
    2. 递归处理 rtrt 的各个子树(不经过 rtrt 的路径)。
    3. 处理经过 rtrt 的路径
      • 收集 rtrt 子树中所有节点 uu
      • 对每个 uu,计算它到 rtrt 的距离 dis(u,rt)=dudrtdis(u,rt) = d_u - d_{rt}
      • 对于 rtrt 到根 11 的祖先链,按 dd 从小到大加入凸壳(因为 dd 向根递减,但加入顺序反过来)。
      • 对每个 uu,找到最小的 dad_a 满足 dadulud_a \ge d_u - l_u(即最近的可跳祖先),在凸壳中查询斜率 pup_u 的最小截距,来更新 dpudp_u
    4. 继续递归 rtrt 的子树。

    关键细节

    • 凸壳按 x=dax = d_a 排序(递增),但祖先链上 dd 递减,所以要从根向 rtrt 加入凸壳。
    • 查询时,需要在凸壳中二分找到斜率 pup_u 的最优点。
    • 由于 lul_u 限制,可能只需凸壳的一段,因此还需二分左边界。

    7. 复杂度分析

    每次分治,凸壳构建 O(m)O(m)mm 为当前层点数),查询 O(mlogm)O(m \log m),总复杂度 O(nlog2n)O(n \log^2 n)

    如果用可持久化凸壳(主席树)可以做到 O(nlogn)O(n \log n),但实现复杂。


    8. 总结步骤

    1. DFS 预处理 dud_u
    2. 初始化 dp[1]=0dp[1]=0
    3. 对整树进行点分治:
      • 找重心。
      • 递归处理子树。
      • 构建祖先链凸壳。
      • 用祖先凸壳更新子树节点 DP 值。
    4. 输出 dp[2..n]dp[2..n]

    9. 注意事项

    • 距离和费用可能很大,用 long long 存储。
    • 二分斜率比较时注意避免浮点数误差,用交叉乘法比较。
    • 凸壳维护时注意弹栈条件。
    • 树分治中注意标记已访问的重心,避免重复。

    这种“DP + 斜率优化 + 树分治”的组合,是解决树上路径限制优化问题的经典模式。

    • 1

    信息

    ID
    5707
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者