树链剖分学习笔记

先让我们看一个题目

有一棵n个节点的树,树的每条边有个边权,有如下两种操作

1.修改一条边的边权

2.查询两点之间路径的权值

对于这种题目,可能有人会选择直接暴力,这很明显不行。

换一种思路,如果我们把树的每一条边拆下来,对他们进行编号,然后使用线段树来存储呢?使用线段树来对每条边的边权进行修改和查询是很方便的。于是这样我们就引出了树链剖分

树链剖分其实就是把一棵树上的各个边拆开来进行处理,从而对树的整体进行划分。

将树划分为链,用数据结构来维护这些链,时间复杂度大致为O(log n) 。

在这里主要学习树链剖分里的轻重链剖分。

我们把树中的每一条边分为两种:轻边重边

假设有一棵树U,我们用Size(U)来表示它的大小(即结点个数)。

令V为U所有子节点中大小最大的一个,则我们称边(U,V)为树U上的一条重边,其他的边均为轻边。V为重子节点,其他节点均为轻子节点。

下面引用IOI2009国家集训队论文漆子超《分治算法在树的路径问题中的应用》的一点内容来阐述轻重链剖分的性质:

性质1.如果边(U,V)为一条轻边,则有Size(V)≤ Size(U)/2

性质2.从根到某一点的路径上轻边的个数不会大于O(log n)

性质3.我们称某条链(原文中是路径)为重链,当且仅当这条链完全由重边组成。那么对于每个点到根的路径上都有不超过O(log n) 条轻边和O(log n) 条重链

让我们来证明一下这三条性质。

对于性质1,假设U有n个子节点,则V max  在二叉树的情况下是最大的,又是轻边,故Size(V)≤ Size(U)/2;

对于性质2,假设(U,V)是一条轻边,那么Size(V) max  =Size(U)/2;要保证Size(V)≥ 1,那么最多也就向下拓展log n 的深度,最好情况下整条链为轻链,即完全由轻边构成,这时有log n 条轻边;

对于性质3,挂个图

很容易的可以看出树链剖分和树上分治的一点关系

在做树上分治的时候,我们是一次删除一条边(边分治)或者一个点(点分治),而在做树链剖分的时候我们一次删除一整条链,可以将其看做树上的链分治。通过这种方法,我们大大降低了在树上对边权进行操作的复杂度。

关于树链剖分各种情况下的复杂度,QuarterGeek的一篇文章有过列举

QuarterGeek

因为这东西本身没有功能,具体功能都是靠具体数据结构实现的,所以复杂度就是O(logn * ??)。如果套上了线段树,就是 O(log^2 n)。如果套上了树套树,那就是O(log^3 n)。如果你用树链剖分和树套树写区间第k大,那就是O(log^4 n)。

接下来我们简单介绍一下链剖的实现过程。

  1. 第一次DFS,在DFS拓展过程中求出每个节点的大小Size,深度Deep和祖先节点fa(用倍增的方法表示)。
  2. 第二次DFS,从根节点开始向下拓展构建重链。每次我们选择一个Size最大的子树继承上一次的重链,其他轻子节点单独构建新的重链。在DFS同时我们给每一个节点打上一个标号,这样节点就可以用来表示区间,使得每一条重链变成了一段区间,我们就可以将重链取下来放在线段树中维护。
  3. 权值的修改。单点权值的修改可以直接在树中完成操作。边权的修改我们要分两种情况讨论:假设我们要修改边(U,V)的边权。若U,V在同一条重链上,那么我们可以直接在线段树中修改区间[u,v] 的值;若U,V不在同一条重链上,我们可以用类似平衡树里提根的操作将他们向上提,直到两个点在同一条重链上,然后重复第一种情况的操作。
  4. 路径长度查询。与权值相似的,若U,V在同一条重链上,直接在线段树内查询;若不在一条重链上,提点然后查询。

    写到这里已经很晚了= =没时间再去做一个例题写个模板上来了真是抱歉啊。题目什么的后面写解题报告里面吧。

时间: 2024-10-25 07:20:25

树链剖分学习笔记的相关文章

树链剖分 学习笔记

像我这么懒肯定不会有图辣 在GCZ大爷的安利下来学树剖,慢慢补吧... 前言 这几天边看<高级数据结构>,边看各路神犇的Blog,终于看懂一点点了.不得不说那本书作者的码风是真的垃圾. 树链剖分,是一种将树剖分成多条不相交的链的算法,并通过其他的数据结构来维护这些链上的信息. 最简单的例子就是LCA,假设现在有一棵退化成链的树.如果要求任意两点的LCA,因为他们在同一条链上的缘故,只需要判断一下两者的深度就行了.由此可见,在链上是比在树上更好操作的. 那么该怎么将一棵树剖分开来捏? 先搬出一堆

树链剖分学习记录

HDU  3966 基于点权 修改(增减)一条路径上的点  单结点查询 code: #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 50010; struct Edge{ int to, next; }e

树链剖分学习&amp;BZOJ1036

题目传送门 树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组.SBT.SPLAY.线段树等)来维护每一条链. 以下是几种概念: 常见的路径剖分的方法是轻重树链剖分(启发式剖分) 将树中的边分为:轻边和重边 ?定义size(X)为以X为根的子树的节点个数. ?令V为U的儿子节点中size值最大的节点,那么边(U,V)被称为重边,树中重边之外的边被称为轻边. 性质:?轻边(U,V),size(V)<=size

树链剖分学习

解决的问题 对于给出的树上两点求之间的最值或者更新操作变为logn. 其他方法 Tarjan求LCA的复杂度为 O(N+Q)所以不断更新复杂度太高. 本质: 就是将树划分为不重合的多条链每条链都有一个线段树中的编号(可类比dfs序转换线段树的想法)+线段树.在求的过程中根据重链不断逼近再用线段树维护即可. 入门文章 练习题目 一般有对点建树和对边建树两种方案,看题目要求.对第几条边进行操作这种情况要将边存储下来. 其实就是一个点的影响范围.线段树的话更新要更新到单点. 模板 #include <

[学习笔记]树链剖分

基本思想 树链剖分一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每条边属于且只属于一条链,然后再通过数据结构来维护每一条链. 一些定义 树链:树上的路径. 剖分:把路径分类为重链和轻链. 重儿子:u的子节点中siz[v]值最大的v. 轻儿子:u的其它子节点. 重边:点u与其重儿子的连边. 轻边:点u与其轻儿子的连边. 重链:由重边连成的路径. 轻链:轻边. 性质 如果(u,v)为轻边,则siz[v]$\times$2<siz[u]. 从根到某一点的路径上轻链.重链的个数都不大于l

树链剖分(轻重链剖分)算法笔记[转]

仔细想想 自己第一次听说这个这个数据结构大概有两年半的时间了 然而一直不会. 不过现在再回头来看 发现其实也不是很麻烦 首先 在学树链剖分之前最好先把LCALCA 树形DPDP 以及dfsdfs序 这三个知识点学了 如果这三个知识点没掌握好的话 树链剖分难以理解也是当然的 ------------------------------------------------------------------------------------------- 树链剖分通常用于处理树的形态不变 但点权/

HYSBZ 1036 【树链剖分】

思路: 裸裸的树链剖分.... 树链剖分就是把一棵树分成若干重链和轻链...然后保证形成的线段树上每条链是连续存储的.然后这样就能用线段树进行维护了. 但是每次一定要保证是在同一条链里边....思路就是这样.... 感觉最近越来越淡定了,题目卡住了也不怎么着急了,慢慢看代码...嗯...有点像学习的感觉了.... 明天青岛理工的邀请赛要好好玩玩... #include<stdio.h> #include<string.h> #include<algorithm> usi

树链剖分专题

学习了一下树链剖分,找了几个有意义的题目训练一下 前4题是基础训练, A.B是AOV树(点记录信息) C.D是AOE树(边记录信息) *注意一下poj好像是提交的代码包含/**/这样的注释会出问题 A.HDU 3966 题意:给你N个点M条边的一棵AOV树,有P次操作 操作分别是:‘I’:将C1到C2路径上的点增加K:     ‘D’:将C1到C2路径上的点减少K:     ‘Q’:问你C点上的权: 解:树链剖分基础题,需要注意的是杭电的服务器是windows的,代码中加入用下面这句话扩栈 #p

树链剖分小结

这两周在学树剖. 先扔个模板 有一类题目,要求实现一类在树上的操作,比如: 修改/求 树上某 节点/边权 的(最)值: 修改/求 树上某 节点/边权 及其子树上所有节点的(最)值: 修改/求 树上某两点路径间的 节点/边权 的(最)值: 乍一看似乎用线段树就可以实现,但是如果仔细想想,可以发现单凭线段树是无法解决的. 对于这类题目,常用的解决方法是树链剖分. 树链剖分(节选自starszys博客): 相关定义: 重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子. 轻儿子:v