您的位置:首页 > 其它

树链剖分

2016-05-20 19:16 218 查看

关于链剖

链剖实质上是通过轻重链的划分,将树剖成一条条重链,首尾相连存进数据结构(线段树、树状数组、splay之类的),支持路径查询,修改等

如何实现?

定义以下几种东西

重儿子 子树大小最大的儿子

轻儿子 除重儿子其他的都是轻儿子

重边 每个点连向它的重儿子的边

轻边 连向轻儿子的边

重链 重边组成的链



这里总共有5条重链,1-2-4-8、5、9、3-6-10、7

我们按照优先重链的DFS序重新标号,用DFN[]数组记录,例如DFN[8]=4,DFN[7]=10

定义几个数组top[],son[],deep[],size[],分别表示所在重链顶端,重儿子编号,深度,子树大小

我们可以一次DFS求出son[],deep[],sizep[]

再一次DFS求出top[],dfn[],这两个DFS非常简单,自己随便YY一下

然后就可以根据DFN的顺序依次丢进数据结构里面。

重点在于,如何路径修改和路径查询

一般的都是要做一个LCA的,然而链剖并不需要

设当前要修改的路径起点u,终点v

如果u,v在同一条重链上,即top[u]=top[v],那么可以直接在数据结构上区间修改dfn[u]到dfn[v]这一段。

如果u,v不在同一条重链上,需要比较deep[top[u]],deep[top[v]]

不妨总是使deep[top[u]]>=deep[top[v]],不是的话就交换

那么我们区间修改dfn[top[u]]到dfn[u],再把u跳到father[top[u]]

重复操作,直到u=v

查询也是一样的。

复杂度是O(Nlog2N)的

下面有一个例题

[ZJOI2008][JZOJ2256][BZOJ1036]树的统计

代码见这里
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: