树链剖分

jys posted @ Feb 20, 2013 09:06:08 PM in 未分类 , 1343 阅读

最近两天写了几道树链剖分,终于能够写出一个两百行的程序不用陷入无尽调试了。

树链剖分需要对于每个点求出如下几个域:

dep:此点深度

siz:此点子树的点数

fa:此点的父亲

son:此点重儿子的编号

top:此点所在重链顶端的点编号

w:如果题目要维护的权值在点上:表示此点在所在重链中的编号

   如果题目要维护的权值在边上:表示此点与其父亲的连边在其所在重链中的编号

belong:此点(或此点与其父亲的连边)所属重链的编号

weight:此点(或此点与其父亲的连边)的权值

-----------------------------------------------------------------------------

这些东西的求出可以用两次DFS求,也可以用一次BFS生成BFS序列,再对序列正反两次扫描得到。但是由于树链剖分的题点数较大,DFS可能爆栈,故推荐BFS方法。

-----------------------------------------------------------------------------

对于每一条重链可以用线段树维护,但需要考虑空间消耗问题。也可以把所有的链放在一个线段树里维护,但是会加大常数。

-----------------------------------------------------------------------------

对于一个查询(u,v)来说,可以先求LCA再逐步提升两个点,也可以这么做:

令f1=top[u],f2=top[v],如果f1==f2那么两个点已经在一条链上,链内查询;否则不妨设dep[f1]<=dep[f2],则先链内查询将v提至f2,然后通过一条轻边将f2提至fa[f2],重复此过程。

这么做最后两个点一定都停在他们的LCA处,因此树链剖分也可以用来在线求LCA,每一条重链不加任何数据结构维护,空间消耗O(n)。

----------------------------------------------------------------------------

永远不要用std::vector来存储边。

----------------------------------------------------------------------------

树链剖分一般长度会有150+。但是写熟之后就没什么感觉了。

----------------------------------------------------------------------------

END。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter