1 条题解

  • 0
    @ 2025-8-24 21:51:06

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar xgzc
    苔花如米小,也学牡丹开。

    搬运于2025-08-24 21:51:06,当前版本为作者最后更新于2019-03-31 15:10:14,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    神仙题目啊QwQ

    fi(x)f_i(x)表示以第ii个点为根的子树需要xx秒引爆的代价。

    我们发现,这个函数是一个下凸的一次分段函数。

    考虑这个函数合并到父亲节点时会发生怎样的变化。

    fi(x)f_i'(x)是原函数,fi(x)f_i(x)是新函数,ii和父亲之间的边长度为ll[L,R][L, R]fi(x)f_i'(x)斜率为00的那一段的左右端点的横坐标,那么有:

    $$f_i(x) = \begin{cases}f_i'(x) + l & x \leq L \\f_i'(L) + (l - (x - L)) & L < x \leq L + l \\f_i'(L) & L + l < x \leq R + l \\f_i'(L) + ((x - R) - l) & R + l < x\end{cases} $$

    我们一个一个来看。

    首先第一个,当xLx \leq L时,我们肯定要让新的ll越小越好,因为改变ll的代价为11,而这个函数在L\leq L的时候斜率1\leq -1,即修改一次xx的代价1\geq 1,所以干脆将ll变成00

    第二个,我们只要保证x=Lx = L就能取到函数的最小值,于是ll的变化量越小越好。

    第三个,我们不用改变ll就可以保证能取到最小值,那就不用改变了。

    第四个和第一个很像,这里就略去了。


    那么这个过程究竟对这个函数做了什么改变呢?

    我们将L\leq L部分的函数向上平移了ll单位,将[L,R][L,R]部分向右平移ll单位,在[L,L+l][L,L+l]部分插入了一条斜率为1-1的直线,并将>R+l> R + l的部分的斜率改为了11

    于是大概变成了这个样子(图源网络):

    这样,各个拐点之间的直线的斜率是从左到右递增的。

    我们不妨假设各个拐点之间的直线斜率的增量为11,如果有一个斜率不存在,那么我们就用两个同一位置的拐点来表示这个不存在的斜率。

    然后我们发现我们只可能存下拐点的横坐标,于是怎么求函数值是一个问题。

    我们如果能知道f(0)f(0)的值,这个事情就好办了。

    f(0)f(0)的值还不好求???就是所有边权之和啊。

    于是我们得到了通过拐点横坐标求得f(L)f(L)的方法,皆大欢喜。

    那么我们知道每个函数被合并上去之前会变成什么样子了,那么我们也可以非常简单的合并两个函数了,我们只需要将两个函数的拐点列表合并一下就可以了。

    我们再看看在合并到父亲节点时要做的操作:

    一、将斜率>0> 0的那一段的斜率改为11

    因为我们合并上来的函数的斜率最大值都为11,所以我们只需要删除k1k - 1个最大的拐点即可,其中kk是这个点儿子的数量。

    二、将斜率=0=0的那一段平移ll单位。

    首先,我们做完一操作之后,横坐标最大的两个拐点就是斜率为00的两个端点了,将它们弹出来,加上ll再放进去就没了。

    三、加入一段斜率为1-1的直线。

    这个其实在做操作二的时候就顺带做完了。

    我们维护一个可并堆就可以做上面的所有操作。

    最后求答案时,我们保留LL及其左边的拐点,依次减去它们的横坐标就是我们想要的函数值了。

    代码见我的blog\texttt{blog}

    • 1

    信息

    ID
    1469
    时间
    1000ms
    内存
    125MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者