首页 > 代码库 > 树链剖分小结

树链剖分小结

这两周在学树剖。

先扔个模板

有一类题目,要求实现一类在树上的操作,比如:

  修改/求 树上某 节点/边权 的(最)值;

  修改/求 树上某 节点/边权 及其子树上所有节点的(最)值;

  修改/求 树上某两点路径间的 节点/边权 的(最)值;

乍一看似乎用线段树就可以实现,但是如果仔细想想,可以发现单凭线段树是无法解决的。

 对于这类题目,常用的解决方法是树链剖分。

   

树链剖分(节选自starszys博客):

相关定义:

  重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
  轻儿子:v的其它子节点。
  重边:点v与其重儿子的连边。
  轻边:点v与其轻儿子的连边。
  重链:由重边连成的路径。
  轻链:轻边。

  树链,就是树上的路径。剖分,就是把路径分类为重链和轻链。
  记siz[v]表示以v为根的子树的节点数

  d[v]表示v的深度(根深度为1)

  top[v]表示v所在的重链的顶端节点

  f[v]表示v的父亲

  son[v]表示与v在同一重链上的v的儿子节点(重儿子)

  id[v]表示:

    1.v与其父亲节点的连边(v的父边)在线段树中的位置;

    2.v在线段树中的位置;

  只要把这些东西求出来,就能用logn的时间完成上述问题中的操作。

  

  实际上,只需要两次dfs就可以求出上述变量。

  dfs1(dfs):求出f、d、siz、son、top、id

  dfs2(build):求出id与top(详见模板)

  然后将原树中各点的值update到线段树中,进行各种操作。

  

时间复杂度:

既然树剖这么好用,那它的时间复杂度如何呢?

可以证明,树链剖分的时间复杂度是O(N·logn·logn)。

经过上面的学习,可以发现树链剖分的结构是沿着链向上跳+线段树修改/查询。

线段树的时间复杂度是O(N·logn),而在树链上每走一条轻边,子树大小就/=2,所以最多走log n条轻边。

  

推荐题目:

  模板题:BZOJ4034、BZOJ1036(LZOJ21004)、BZOJ2243、POJ3237

  稍难:BZOJ3531、BZOJ3626、NOIp2015day1T3、NOIp2016天天爱跑步

树链剖分小结