Link
总算能基本上自己做出来一道题目了虽然是水题
Solution
可以发现,把一棵树从一条边剖开,要合起来最长的直径就是两个子树的直径和 最短的直径就是把两个直径的中点相连。所以主要问题就是快速算直径 设从到的连边把树剖开,的子树中的直径可以预处理,那么另一部分直径有这样几个来源:
- 祖先们除了所在子树之外的子树中的直径
- 的子树刨去的子树剩下部分的直径
- 下面连一条长链,向上伸到一个祖先,再向下连一条长链
观察之后,发现一遍预处理,对于以为根的子树,处理出子树的直径,的子节点的子树的直径的最大、次大值,和从向下的前三长的链,就可以做前两个。 第三个只需要在DP的时候在栈上记录一个从祖先来的最长链即可 大体就是这样 写了一个来小时,然后开启了DEBUG被坑模式
Tips
改来改去,其实主要就改了3个错误,而3个错误的外观是一样的:输出方案里有0。 具体地说,是使得直径最小的连边出现了0。
- 我在DP的时候记录了每个链的一个端点,输出方案的时候需要找到直径的中点,那就再从端点开始DFS一下就好了。然后一开始我把两个直径的端点设置成了不可访问,导致第一个的DFS几乎搜遍了整个树,把第二遍DFS需要找的点也给搜了!!
- 然后我找到了问题,设置成了两个断点不可用,再从端点开始搜,还是出来0。最后发现,把断点设置不可用,直接把一些合法的链截断了!!!!
- 然后我找到了问题,设置了每遍DFS都是另一个断点不可用,还是出来0。最后发现,我的DP中因为存在一些,我盲目地和取了,导致一些不存在的状态被合法化了!!!
- 然后几乎3h就过去了。
通过做这道题题目使我充分认识到自己能犯的错误有多么SX。 所以,至少要总结这几点经验: 想想遍历之前设置不可用的点截断的是什么 DP,尤其是记录方案的DP,即使是0这样的值也一定要有来由!
Code
1 |
|
限制是