1 条题解

  • 0
    @ 2025-12-11 6:54:35

    题解:树上取苹果的最大幸福度

    问题转化

    给定一棵以 11 为根的树,每个节点 iiaia_i 个苹果,每个苹果价值 viv_i。取苹果规则:

    1. 如果在节点 ii 取了至少一个苹果,则必须在其父节点也取至少一个苹果。
    2. 设总共取了 tt 个苹果,取了苹果的节点的最大深度为 hh(根深度为 11),要求 thkt - h \le k

    目标:最大化总价值。

    关键观察

    1. 深度与取苹果的关系

    令取了苹果的节点集合为 SSSS 非空。设 dmax=maxiSdepth(i)d_{\max} = \max_{i \in S} depth(i),则 h=dmaxh = d_{\max}

    条件 thkt - h \le k 可写为 th+kt \le h + k,其中 t=iSxit = \sum_{i \in S} x_ixix_i 是在节点 ii 取的苹果数,1xiai1 \le x_i \le a_i

    2. 规则1的传递性

    规则1意味着:如果节点 ii 取了苹果,则从 ii 到根的整条路径上的每个节点都必须取至少一个苹果。

    因此,SS 必须是一个包含根节点的连通子图(到根的路径连通)。

    SS 是某个深度 hh 的节点为最深节点的连通块(包含根),则所有节点 iSi \in S 必须取 xi1x_i \ge 1,且 SS 外的节点不能取苹果。

    3. 问题转化为选择深度和连通块

    枚举最深深度 hh1h1 \le h \le 树高),选择以某个深度为 hh 的节点 uu 为最深节点的连通块 SS(包含根到 uu 的路径上的所有节点),并在 SS 内取苹果,满足 iSxih+k\sum_{i \in S} x_i \le h + k,最大化 iSxivi\sum_{i \in S} x_i v_i

    由于 vi>0v_i > 0,我们希望在不超过总数限制的情况下,尽量多取苹果,且优先取 viv_i 大的苹果。

    4. 转化为背包问题

    对于固定的连通块 SS,问题变为:每个节点 iSi \in Saia_i 个物品,每个物品价值 viv_i,体积为 11,总容量 C=h+kC = h + k,且每个节点至少选 11 个物品(因为取了至少一个苹果)。

    bi=ai10b_i = a_i - 1 \ge 0 表示额外可以多取的苹果数(已经取了至少 11 个),则问题变为:

    • 首先每个节点取 11 个苹果,基础价值 sumV=iSvisumV = \sum_{i \in S} v_i,已用体积 S|S|
    • 剩余容量 C=(h+k)SC' = (h + k) - |S|,每个节点最多再取 bib_i 个苹果,每个苹果价值 viv_i
    • 在容量 CC' 内,从所有节点中选择若干额外苹果,最大化总价值。

    这是经典的分组背包:每组是节点 ii,有 bib_i 个相同价值 viv_i 的物品(体积均为 11),最多选 bib_i 个。

    5. 贪心选择

    由于每组内物品价值相同,最优策略是优先选择价值 viv_i 大的节点多取苹果。

    因此,对于固定的 SS,将所有节点按 viv_i 降序排序,然后贪心取前若干大的 viv_i 的额外苹果,直到达到容量 CC' 或没有额外苹果可拿。

    6. 枚举连通块

    树高可能较大,但 kk 可达 5×1055\times 10^5n20000n \le 20000

    直接枚举每个节点 uu 作为最深节点,其连通块 SS 就是根到 uu 的路径上的所有节点。
    P(u)P(u) 表示根到 uu 的路径节点集合,P(u)=depth(u)|P(u)| = depth(u)

    h=depth(u)h = depth(u),容量 C=depth(u)+kC = depth(u) + k,基础占用体积 depth(u)depth(u),剩余容量 C=kC' = k

    因此,剩余容量只与 kk 有关,与 uu 无关!
    因为 C=(depth(u)+k)depth(u)=kC' = (depth(u) + k) - depth(u) = k

    所以对于任意节点 uu,可额外取的苹果数不超过 kk

    7. 统一问题

    现在问题简化为:
    对于每个节点 uu,取根到 uu 路径上所有节点至少一个苹果(基础价值 sumV(u)=iP(u)visumV(u) = \sum_{i \in P(u)} v_i),然后还可以额外取最多 kk 个苹果(从路径上的节点取,每个节点 ii 最多额外取 ai1a_i - 1 个,每个价值 viv_i),最大化总价值。

    总价值 = sumV(u)sumV(u) + 从 P(u)P(u) 中贪心选最多 kk 个额外苹果的最大价值。

    8. 转化为树上问题

    我们需要对每个节点 uu 计算:

    ans(u)=sumV(u)+greedy(P(u),k)ans(u) = sumV(u) + \text{greedy}(P(u), k)

    其中 greedy(P(u),k)\text{greedy}(P(u), k) 表示从 P(u)P(u) 中选最多 kk 个额外苹果(节点 ii 最多 ai1a_i-1 个)的最大价值。

    由于 viv_i 都为正,贪心就是取 viv_i 最大的那些苹果。

    9. 维护路径上的价值前 kk 大苹果

    对于每个节点 uu,需要知道根到 uu 路径上所有节点的 (vi,bi)(v_i, b_i) 对,并从中选出最多 kk 个价值最大的苹果。

    由于 kk 很大(可达 5×1055\times 10^5),但 n20000n \le 20000vi100v_i \le 100bib_i 可能很大(aia_i 可达 10810^8),但实际额外苹果数受 kk 限制。

    我们可以按 viv_i 值(11100100)分组。对每个 vv,统计路径上 vi=vv_i = v 的节点的额外苹果总数 cntvcnt_v

    贪心时,从 v=100v=100 向下取,每次取 min(cntv,remaining)min(cnt_v, remaining) 个价值 vv 的苹果。

    10. 树上前缀和

    prev[u]pre_v[u] 表示根到 uu 路径上 vi=vv_i = v 的节点的额外苹果总数 bib_i 之和。

    则对节点 uucntv=prev[u]cnt_v = pre_v[u]

    那么 $\text{greedy}(P(u), k) = \sum_{v=100}^{1} v \times \min(pre_v[u], rem)$,其中 remrem 是剩余可取的苹果数,初始 rem=krem=k,每次减去已取的。

    11. 计算答案

    对每个节点 uu

    1. 计算 sumV(u)sumV(u)(根到 uu 路径上 viv_i 之和)。
    2. 计算 prev[u]pre_v[u] 对所有 v=1..100v=1..100
    3. 贪心取额外苹果:
      rem=krem = k, extra=0extra = 0
      v=100v=10011
      take=min(prev[u],rem)take = \min(pre_v[u], rem)
      extra+=v×takeextra += v \times take
      rem=takerem -= take
    4. ans(u)=sumV(u)+extraans(u) = sumV(u) + extra
    5. 最终答案 = maxuans(u)\max_{u} ans(u)

    12. 预处理前缀和

    DFS 遍历树,维护当前路径上的 sumVsumVprevpre_v 数组。

    由于 vi100v_i \le 100prevpre_v 只有 100100 个值,可以 O(100)O(100) 更新。

    复杂度:O(n×100)O(n \times 100) 预处理,O(n×100)O(n \times 100) 计算每个节点的贪心(因为每次从 10010011 扫描)。

    总复杂度 O(100n)O(100n),可过。

    13. 处理大 bib_i

    bi=ai1b_i = a_i - 1 可能很大(10810^8),但 k5×105k \le 5\times 10^5,所以实际最多取 kk 个额外苹果。
    在统计 prev[u]pre_v[u] 时,如果 bi>kb_i > k,可以截断为 kk,因为再多也无用。

    因此令 bi=min(bi,k)b'_i = \min(b_i, k),再累加到 prev[u]pre_v[u] 中。

    但注意 prev[u]pre_v[u] 是多个节点的 bib'_i 之和,可能超过 kk,所以贪心取 min(prev[u],rem)min(pre_v[u], rem) 即可。

    14. 算法步骤

    1. 读入 QQ,对每组数据:
      • 读入 n,kn, k 和树结构。
      • 对每个节点 ii,计算 bi=min(ai1,k)b_i = \min(a_i - 1, k)(如果 ai=0a_i=0 则不能取,但题目保证 ai>0a_i>0)。
    2. DFS 从根开始:
      • 维护当前路径的 sumVsumV 和数组 pre[1..100]pre[1..100]
      • 进入节点 uu 时,更新: sumV+=vusumV += v_u pre[vu]+=bupre[v_u] += b_u
      • 计算当前节点的答案 ans(u)ans(u)rem=krem = k, extra=0extra = 0v=100v=10011take=min(pre[v],rem)take = \min(pre[v], rem) extra+=v×takeextra += v \times take rem=takerem -= take ans(u)=sumV+extraans(u) = sumV + extra 更新全局最大值。
      • 递归子节点。
      • 回溯时恢复 sumVsumVpre[vu]pre[v_u]
    3. 输出全局最大值。

    15. 注意

    • 根节点必须取至少一个苹果(因为如果取任何苹果,根必须取)。
    • 如果 k=0k=0,则只能取路径上的基础苹果(每个节点恰好取 11 个)。
    • 答案可能超过 3232 位整数,用 6464 位存储。

    复杂度分析

    • 每组数据:O(100n)O(100n)
    • n20000n \le 20000Q5Q \le 5,总操作约 10001000 万次,可过。
    • 1

    信息

    ID
    6078
    时间
    5000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者