码迷,mamicode.com
首页 > 其他好文 > 详细

虚树教程

时间:2019-09-26 21:48:02      阅读:109      评论:0      收藏:0      [点我收藏+]

标签:sdoi   log   构造   朴素   遍历   需要   ant   优化   lan   

问题引入

SDOI2011消耗战

虚树

按照朴素的做法,就是对于每一个询问都跑一边DP。
\[ Dp[i] = Dp[ i ] + \min( Dp[Son],Cost[i,Son]) \,\,\,(Son不为关键点)\Dp[i] = Dp[ i ] + Cost[ i, Son ] \,\,\,(Son为关键点)\Dp[i] = INF\,\,\,(i为叶子) \]
这样时间上显然是不行的。我们需要优化一下。

注意到\(\sum k\leqslant 500000\),那么可能许多点都不是关键点,而我们却浪费了许多时间在它们上面。其实删掉一个关键点,只需要断掉路径上边权最小的边即可。

这么说来,我们可以缩掉很多不是关键点的点。但是为了保持原树的形状,我们同时需要维护每两个点之间的最近公共祖先(LCA)。其实到这里就可以尝试上手了。下面提供一个可能比较优美的虚树构建方法:

首先按照所有关键点的DFS序排序。开一个 Stack ,加入根节点。

顺序遍历排好序的所有关键点,求关键点和栈顶的Lca。记栈顶元素为Top,栈顶第二个元素为 PreTop(如果有的话)。分为以下几种情况考虑:

  • Deep[ Lca ] = Deep[ Top ]:那么直接把当前点加入 Stack 即可。
  • Deep[ Lca ] < Deep[ Top ] : 如果Deep[ PreTop ] > Deep[ Lca ],则在新树种加入边PreTop-Top,并且弹出栈顶元素,直到 Deep[ PreTop ] <= Deep[ Lca ]。 然后再分两种情况 : 1)如果Deep[ PreTop ] = Deep[ Lca ],在新树种加入PreTop-Top,弹出栈顶,然后加入当前点;2)如果Deep[ PreTop ] = Deep[ Lca ], 在新树种加入Top-Lca,弹出栈顶,然后加入Lca和当前点。
  • 最后顺序弹出栈顶,并同时加入边。

那么构造到此结束了。这样如果预处理了Lca,就可以线性构造虚树了。

开头所提的问题可以参考这里

虚树教程

标签:sdoi   log   构造   朴素   遍历   需要   ant   优化   lan   

原文地址:https://www.cnblogs.com/chy-2003/p/11594425.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!