BZOJ1999 树网的核
题意缩简:
给你一个树上偏心距的定义 让你在某一条直径上找一条长度不超过S的线段使得偏心距最小
树上偏心距:树上离某段线段最远的节点的距离
树上节点到线段的定义:节点离线段上最近点的距离
做题之前 我们先得出一个结论:在任意一条直径上求出的最小偏心距都相等
证明:
如果仅有一条直径 明显成立.
如果有两条及以上的直径的话 因为直径必定相交且中点重合(题目给出 也很任意证明)
所以在其中一条直径上求最小偏心距的答案 必定是另一条直径的某一个端点贡献的 把这个两个直接角色互换 答案不变
解法一:朴素(O(n^3))
枚举某一条直径上长度不超过S的线段(O(n^2))
然后再O(n)地直接得到当前情况的答案
解法二:贪心(O(n^2))
在朴素做法的基础上 我们很容易知道 这个线段能尽量长就尽量长这样根据定义扩充后的线段的偏心距会不大于原来的偏心距
所以我们在某一条直径上直接枚举长度为S的线段O(n) 再O(n)地直接得到当前情况的答案
解法三:二分答案(O(nlog(SUM)))
显然 答案具有单调性 所以我们可以二分答案 然后O(n)或者O(1)地check (SUM为树上所有边长之和)
check:设当前二分答案值为mid 如果mid不小于直径长度/2 则直接r=mid O(1)
反之 则找到离直径两端分别为mid的两个点P与Q 连接这两个点作为核 再O(n)得到最小偏心距 看是否大于mid
(可以证明 任意从P或Q到其最近的直径一端分叉出去的子树 其最远点与P或Q的距离不会超过P与其最近的直径一端的距离)
解法四:单调队列O(n)
我们先求出一条直径O(n)dfs直径上的点得到一个数组d
d[i]表示从i点出发不经过直径上的其他点能够到达的最远点的距离
然后直接搞一个单调队列 维护长度为S时每段的答案O(n)