description
给一棵
n
n
n个结点的树,每个结点有一个正整数权值。要求选出一个结点的集合,满足:
1.这个集合包含
1
1
1号结点
2.这个集合在树上是一个连通块。
即,设这个集合为
S
S
S,则树上存在
∣
S
∣
−
1
|S|-1
∣S∣−1条边,这些边连接的结点都属于
S
S
S。
记一个集合的权值为该集合内所有结点的权值和。
求权值第
k
k
k小的集合的权值。
solution
明显二合一。那么我们现在有两个问题。第一个是
k
≤
3
e
5
k\leq3e5
k≤3e5,第二个是答案
≤
500
\leq 500
≤500。
那么第二个貌似就挺好做的,树上背包一下就完了。我写的时候复杂度是
O
(
n
×
r
e
s
log
r
e
s
)
O(n \times res \log res)
O(n×reslogres),就是背包用FFT优化一下,不知道有没有更优的复杂度,有的话请告知。
那么现在看第二个问题。
明显是像 noi 2010 超级钢琴 那样维护一个堆,每次把最小值弹出,加入可能的新答案。然而这时发现不好记录状态以及不知道怎么找新的可能的答案。一种显然的想法是记录一下可以扩展的“轮廓线”,但是这样是O(n k log)的。那么我们考虑建如下新的树:i -> dfn[enddfn[i] + 1],即i在新树的父亲是dfs序上他的子树之后的第一个点,特别的,设一个新的点n + 1。那么现在我们发现我们的轮廓线变成了新树一些链!
从而我们维护一下这些链,记录x , u , v表示选了x,然后在新树的链上的前驱+1,后继-1。实际上就是可以扩展的点。那么如何新增答案?那么分为两种情况:1)x并不是最终轮廓线上的点,那么沿着其dfs序走一格。2)在u,x或者x,v中加入一个新的轮廓线上的点。
那么分析一下发现这样的确不重不漏。