ARC098F Donation [贪心,思维]

可能是上个月或是上上个月做的了,但是忘记发题解了。

这题好神啊……

思路

我们可以观察出一个性质:每个点只会在最后一次经过的时候捐赠。

由于\(a\)的限制比较奇怪,我们令\(c_i=\max(a_i-b_i,0)\),然后限制转化为任意时刻钱都要至少为\(c_i\)。(包括刚捐赠完的时候。)

考虑此时走一条边的限制就是钱要至少\(\max(c_u,c_v)\),显然从一个点走到另一个点会走最大边权最小的路径,所以可以把图变成一棵树。

现在,每次捐赠就只能捐叶子,然后把这个叶子删掉。然而这棵树是没有根的,所以不能用把儿子和父亲合并的贪心技巧,很难受。

假设捐赠序列是\(\{1,2,\cdots,n\}\),那么答案就是\(\max_i \{ c_i+\sum_{j=1}^i b_j \}\)。这个东西肯定只会在后缀最大值的地方取到最大。(为什么是这个式子?因为走路的时候经过的点还没有被捐赠,所以走路的过程一定不会是瓶颈,所以瓶颈只会在捐赠完的时候。)

我们把\(c\)的最大值\(c_x\)拿出来。我们发现如果在\(x\)之前,它的每个子树里面都有点被捐赠过,那么一定可以把一棵没有捐完的子树内的点丢到\(x\)后面去,此时仍然合法并且答案不会更劣。(注意其他子树必须都是捐完了的)

由于前\(x\)个的最大值只会在\(x\)处取到,所以其他子树的捐赠顺序并不重要,我们只关心\(\sum b\)

捐完\(x\)之后,就只剩下那一棵被丢到后面去的子树了,这是一个子问题。

于是这是一个类似点分治的过程:把最大的点拿出来,和子树内的最大点连边,就可以建出一棵新树,然后在这棵新树上DP。

不过其实原树根本没有必要真正建出来,只需要从小往大加点然后用并查集维护一下就行了。

(这样证明大概比很多其他题解严谨一些?)

https://www.cnblogs.com/ivorysi/p/9849403.html Orz

代码

咕了。

猜你喜欢

转载自www.cnblogs.com/p-b-p-b/p/12187747.html