Description
给定一棵n个节点的树,边有边权(可能为负)。
你需要删掉恰好K条边,再连上恰好K条边权为0的边,并保证连完边后这还是一棵树,求这棵树的最大的最长路长度。
,
Solution
转化模型
删K条边再加K条边,那么对于新树上的一条路径,一定可以用原树上K+1条点不相交的链来表示它(注意一个单点也可以看做一条链,因此路径长不够的时候可以用单点来补)
那么问题就转化为在原树上选恰好K+1条链,使总长最大。
注意到如果我们直接设为当前做完以为根的子树,选了j条链,i这个点接的链的情况(没有/被子树中不超过一条链接上/被子树中不超过两条链接上(即它不能再接出父亲))
显然这样状态数是的,不能满足要求
考虑优化:
感受一下,如果把K作为横轴,x=K下的最优答案作为纵轴,那平面上就有了n个点,这n个点构成了一个凸包。
也就是说,这是单峰的,并且相邻点连线斜率不增。
可以反证,对于选链的情况进行讨论,再分析一下增量,发现更优的选择一定会在更早选,具体不再赘述。
我们发现,如果没有链数限制,我们可以在的时间内求出整体最优解(即凸包最高点的值,也可以求出它用了多少条链)
假如我们将整个凸包整体旋转某个角度(横坐标不变),使我们需要的x=K的点成为整体最高点,那我们就可以快速算出来了。
整体旋转某个角度,等同于用一条过原点的直线去切这个凸包
如下图
实际上,就是对于每一个点,将纵坐标减去横坐标*这条的直线的斜率
考虑这样做在原题目中的体现,相当于每选一条链还需要另外支付一个代价(斜率),求最优解。
此时我们可以二分这个代价(斜率),求出最高点,看最高点的横坐标(选的链数)<K还是>K,来调整二分的斜率。
直到最后,我们二分出了一个恰当的斜率,使得最高点的横坐标为K,那么输出纵坐标+K*斜率即可。
注意到对于这一题,相邻两个点的横坐标差一定为1,且最优值都是整数,那么我们也只需要在整数中二分斜率。
有一种特殊情况,就是连着很多个点斜率相同,K又不在两端,那么此时算出的最优解横坐标不一定是=k的,但我们发现,这些点纵坐标相等,加上横坐标*斜率以后,仍然能得到横坐标=k时的解,因此是没有问题的。
这样总复杂度就是
Code