题面
有 $n$ 个结点的一棵树,每条边有两个权值 $a$ , $b$ ,第 $t$ 天经过第 $i$ 条边花费时间 $a_it+b$ ,给定 $m$ ,求 $t=0,1,2…m−1$ 时,最长的路径长度。
题解
这题一股浓郁的OI气息啊……(思路简单实现复杂的数据结构题)
通过分析题目,本题可以用边分治+斜率优化来解决。
简介边分治
类似点分治选择重心,边分治选择一条边,把树分成两边,使得两边的点数最接近。
但对普通的树进行边分治容易退化,如下面这种图会退化为 $O(n)$(官方题解称为star tree)
所以使用边分治,需要将一般树,转化为二叉树,这样边分治分成的两块,保证了两块的节点数一定在 $[\frac n 3,\frac n 2]$ 之间。
边分治相对于点分治的优点在于,它只会把树分成两块,在有些情况下,合并结果时,减少大量代码量。
本题的边分治
在多叉树转二叉树时,对于本题,我们必须保证任意两点的距离不变,转二叉时需要新建节点,如下图:
对于边分治的一棵数,计算每个子树的大小 siz[u]
,找到最大的子树并且大小 < 总大小的一半,选择这个结点和它父亲结点的边作为重心边,分成两棵树。
对于分成的两棵树
易知,最长路经一定是从根走到叶子节点的路径,统计所有路径,把a值和b值分别加起来,得到这条路径的函数 $at+b$ 。
这两棵树,我们都可以得到一大堆路径的函数,合并两个路径即分别相加他们的a值和b值,现在考虑如何 $O(n)$ 合并所有路径。
设 $a_i<a_j$
对于每个函数$at+b$,将其看作一个点$(a,b)$,根据斜率式,将维护上凸包,斜率递减
将分成的两棵树分别得到的所有路径函数,分别建立两个凸包。
合并时,用两个变量$x,y$,表示当前合并到这两个凸包的第几个结点,每次判断$x$与$x+1$的斜率$k1,y$与$y+1$的斜率$k2$,选择斜率更大的$+1$,再将新的$x$结点与$y$结点合并(选择斜率大的合并,保证了在新凸包中斜率变化量更小,才能使凸包中结点不漏选)
做完边分治,我们得到了整棵树所有有用路径的函数凸包,已经保证了答案的单调,直接计算即可。
代码
安利一下,代码写得很长时,变量名最好写详细一些
1 |
|
转载自can919