模板:树链剖分

“如果你会了树上dp,还会线段树……”

“没错!我都会啊!”

“……那你为什么写不出树链剖分?”

“???”

——by勇者和路由器的对话,今天二位仍然过得十分愉快

————————————————————————————

因为路由器编不出来什么好题面了,所以就扔上来了一个模板题然后和勇者去玩了。

(下面有树链剖分的板子代码+注释,这里只提供讲解)

[ZJOI2008]树的统计Count:http://www.cnblogs.com/luyouqi233/p/7886531.html

我们发现题中要求的内容类似于线段树:单点修改,区间询问。

但是,这是一棵树啊!我们怎么才能在树上建一个只适用于一维的数据结构呢?

我们要抛弃线段树吗?

……

那么我们要试图把树拍扁成一维的吗?

……只能这样了。

其实拍扁成一维并不难想,考虑当树为一条链的时候吗,我们就直接上线段树即可。

那么类比一棵完整的树时,我们就把它分解成一条一条链然后拼在一起线段树维护即可。

关键问题在于要如何分解成链才能使得我们查询既快捷又方便呢?

这里当然就是树链剖分的活啦!

 

树链剖分:

概念:

定义size(X)为以X为根的子树的节点个数。 ž令V为U的儿子节点中size值最大的节点,那么边(U,V)被称为重边,树中重边之外的边被称为轻边。

我们称某条路径为重路径,当且仅当它全部由重边组成。

性质:

性质 1:轻边(U,V),size(V)<=size(U)/2。

ž性质 2:从根到某一点的路径上,不超过O(logN)条轻边,不超过O(logN)条重路径。

对于性质1,我们肉眼观察法和反证法都能解决。

对于性质2就不是那么明显了,我们来证明一下:

由性质1可知,每经过一条轻边,子树的节点个数至少减少一半,所以至多经过 O (log n ) 条轻边。

而进入(或从……出去)一条重路径,一定需要经过一条轻边,所以至多经过 O (log n ) 条重路径。

有了以上两个性质之后,我们就可以发现这种分法的优越性了,我们仅仅只需要搜大概logn级别即可。

细节:

预处理:

我们具体需要求出7个值,分别为:

对于节点u:

父亲fa;

深度dep;

子树节点数size(又叫重量);

重儿子son;

所在重路径的顶部节点top;

在序列的位置pos(下标)。

对于序列的一个下标:

对应树的位置idx。

——————————————————

前四个朴素dfs即可解决,后三个根据节点的重儿子再dfs即可解决。

注意:我们的目的是为了将树分解成重路径,所以第二次dfs建序列的时候要先加重儿子再管其他节点。

 

求值:

我们将u到v的路径分解成:

当u与v不在同一个重路径时:

(u所在的部分重路径)+(top[u]到top[v])+(v所在的部分重路径)。

当u与v在同一个重路径时(显然不需要分解)

按照上面的方法递归并且不断求出这些段的值完后汇总即可。

那么我们就想先跳u为top[u]还是跳v为top[v]——方法就是,为了防止跳大了,跳得越少越好(比较top[u]和top[v]的dep即可)。

 

例题(难度递增):

BZOJ1036:[ZJOI2008]树的统计:http://www.cnblogs.com/luyouqi233/p/7886531.html

BZOJ2243:[SDOI2011]染色:http://www.cnblogs.com/luyouqi233/p/7891126.html

CC DGCD:Dynamic GCD:http://www.cnblogs.com/luyouqi233/p/7896160.html

posted @ 2017-11-23 19:59  luyouqi233  阅读(265)  评论(0编辑  收藏  举报