1 条题解

  • 0
    @ 2026-5-16 22:51:54

    好的,我们先来分析题意和标程的思路,然后给出详细的题解。


    题目重述

    有一棵有 nn 个节点的有根树,节点编号 1n1 \dots n,根为 kk
    定义节点 vv 的“神圣度” d(v)d(v) 为从根到 vv 的路径上最小的节点编号。
    总神圣度定义为:

    v=1nd(v)=m\sum_{v=1}^{n} d(v) = m

    给定 n,mn, m,要求构造这样一棵树,输出根和 n1n-1 条边,若无解输出 1-1


    关键观察

    1. 根的神圣度
      rr 的路径只有自己,所以 d(r)=rd(r) = r

    2. 最小值的传递性
      ppvv 的父节点,则

      d(v)=min(d(p),v)d(v) = \min(d(p), v)

      也就是说,从根到 vv 的路径上,一旦遇到一个比当前最小值更小的节点,后面的节点神圣度都会变成这个更小的值。

    3. 结构等价
      如果根是 rr,那么整个树的节点都会“继承” rr 作为最小值的一部分,直到碰到一个比 rr 更小的节点。
      但根是 rr,路径上的最小值不可能小于 rr,除非某个后代节点编号更小?
      不对,编号是固定的,编号 1 的节点一定在任何包含它的路径上成为最小值,因此如果 1 在某个子树里,那该子树的所有节点神圣度都是 1。


    更简单的视角

    设根为 kk,那么:

    • 节点 kkd(k)=kd(k) = k
    • 节点 <k<k 会怎样?
      注意:如果某个节点 x<kx < k,它一定不在根到其他节点的路径上作为祖先(否则它会更早成为最小)。
      实际上,我们可以这样构造:
      根为 kk,然后我们尝试所有节点 ii 放在哪里。

    观察一个简单构造:

    • 把 1 直接挂在 kk 下面,那么 d(1)=1d(1)=1(因为路径 k1k \to 1 最小值 1)。
    • 2 如果挂在 1 下面,则 d(2)=min(1,2)=1d(2) = \min(1,2)=1,这样 2 贡献 1 而不是 2。

    所以为了使得 d(i)=id(i) = i,节点 ii 必须放在一条路径上,且这条路径上的所有祖先都 i\ge i


    转化问题

    如果我们把 d(i)d(i) 看作节点 ii 的“分值”,那么根的分值 = 自身编号,其他节点如果挂在编号更小的节点下,分值会被拉低。

    更精确地说:

    • 若节点 uuvv 的祖先且 u<vu<v,则 d(v)ud(v) \le u
    • 为了最大化总和,我们希望每个节点 ii 的分值尽量大,即让它放在一条编号递增的路径上(祖先都 > 它,但实际上 ii 比祖先小也不行,所以不可能有祖先都 > 它,除了根更大,根自己是特殊的:根的分值固定)。

    换个思路:
    考虑一条从根出发的路径 ka1a2k \to a_1 \to a_2 \to \dots,那么路径上的神圣度是 k,min(k,a1),k, \min(k, a_1), \dots,所以除非 a1<ka_1 < k,否则不变。
    a1<ka_1 < k 的话,所有后代都会变成 a1a_1

    所以实际上,整个树被分成若干“区域”,每个区域由该区域中最小的节点编号决定该区域所有节点的神圣度。


    标程的思路

    标程用了一个贪心构造:

    1. 先判断合法性:

      • 最小总和:当所有节点都直连根时,d(v)=min(,v)d(v) = \min(\text{根}, v)。如果根 = 1,则所有节点最小值为 1,总和为 nn,这是最小可能(因为 d(v)1d(v) \ge 1)。
        实际上最小总和是 nn:把 1 作为根,所有节点直连根,d(v)1d(v) \ge 1,且根 1 贡献 1,其它节点 v2v\ge2 贡献 1,总和 nn
      • 最大总和:当树是一条链 12n1-2-\dots-n 且根为 nn 时,每个节点 ii 的路径上最小值为自身,总和 1+2++n=n(n+1)/21+2+\dots+n = n(n+1)/2
      • 所以必须满足 nmn(n+1)/2n \le m \le n(n+1)/2
    2. 然后尝试构造:

      • 设根为 rrd(r)=rd(r)=r,其它节点我们可以分配“增量”。
        k=mnk = m - n,表示除了每个节点至少贡献 1 以外,还需要多贡献 kk 的总和。
      • 因为每个节点至少贡献 1,现在考虑如何增加。

      实际上更直接的做法(标程):

      • 先把所有节点贡献设为 1,总和为 nn,需要额外总和 k=mnk = m-n
      • 如何增加?
        把某个节点 xx 从贡献 1 增加到贡献 xx,需要保证它到根的路径上最小值是 xx,即路径上所有节点编号 x\ge x,且 xx 本身在该路径上。
        这等价于把它放在一条所有祖先 x\ge x 的路径上,且它自己是该路径上最小的。 但最简单:让节点 xx 成为某个路径的起点,且挂在 x+1x+1 或更大下。
        实际上标程用了贪心:从大到小取节点作为链的一部分,每个节点贡献 ii 而不是 1。

    标程的构造细节

    标程代码(已给)中:

    i64 k = sum - n;
    vector<i64> ans;
    i64 curr = 0, nsum = 0;
    for(i64 i = n - 1; i >= 0; --i) {
        if(curr == k) break;
        if(curr + i <= k) {
            curr += i;
            ans.push_back(i + 1);
            nsum += i + 1;
        }
    }
    i64 ct = ans.size();
    for(i64 i = 0; i < n - ct; ++i) ans.push_back(1);
    

    这里:

    • k=mnk = m - n 是需要额外增加的总和。
    • 从大到小尝试取 i+1i+1 作为链上的节点(因为 iin1n-1 到 0 对应节点 n,n1,,1n, n-1, \dots, 1),如果当前 +ik+i \le k 就取这个节点作为链的一部分。
    • 最后不足 nn 个节点用 1 补齐(表示其余节点直连根)。

    然后输出:

    • 首先输出根 = ans[0](即最大那个节点)。
    • 然后依次输出链上的边。
    • 当遇到 1 时,把剩下的所有未用节点挂在 1 下(形成 1 的子树)。

    为什么这样构造有效?

    因为:

    • 根是最大值 rr,链上节点 r>a1>a2>r > a_1 > a_2 > \dots,那么每个链上节点的路径最小值 = 自身,贡献自身。
    • 挂到 1 下面的节点,路径经过 1,最小值变为 1,贡献 1。
    • 其他没被链选中的节点(除了 1 外)如果直接挂在根下,路径只有根和它,最小值 = min(根, 它),因为根最大,所以最小值 = 它自己,贡献自身?等等不对——根 > 它,所以路径上最小是它自己,所以贡献自身。那就不只是 1 了。
      这里要仔细看标程:
      实际上标程把链上节点挂在前面节点下,剩下的 1 补齐,然后当 1 出现时,把剩下所有未访问的节点(包括本身未访问的)都挂在 1 下,这样它们的路径经过 1,最小值 1。

    这样:

    • 链上节点:贡献 = 自身编号。
    • 1 下面所有节点:贡献 = 1。
    • 其它情况(比如不在链上也不在 1 下的节点)不存在,因为所有节点要么在链上要么在 1 下。

    总和 = 链节点和 + (剩余节点数) × 1。
    链节点和 = n+kn + k 因为初始 nn 个 1,加了 kk 得到。


    合法性条件

    因此得到:

    nmn(n+1)2n \le m \le \frac{n(n+1)}{2}

    是充要条件。


    最终题解流程

    1. 如果 m<nm < nm>n(n+1)/2m > n(n+1)/2,输出 -1。
    2. 否则:
      • k=mnk = m - n
      • 贪心选链:从 nn 往下取,只要选 ii 不超 kk 就加入链。
      • 剩余的节点用 1 补齐。
      • 输出根 = 链第一个节点。
      • 输出链的边。
      • 当遇到 1 时,把剩余未输出过的节点(除了 1 自身)都挂到 1 下。
      • 结束。

    时间复杂度

    • 预处理 O(n)O(n),总 nn 不超过 10610^6,可行。

    如果你需要,我可以帮你把上述题解整理成最终输出的形式,并附上代码实现。

    • 1

    信息

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