树的经典问题和方法

Posted JebediahKerman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树的经典问题和方法相关的知识,希望对你有一定的参考价值。

树的经典问题和方法

《算法竞赛入门经典(第2版)》392页

欧拉序列。对有根树t进行dfs(深度优先遍历),无论是递归还是回溯,每次到达一个结点时都将深度记录下来,可以得到一个长度为2n-1的序列,称为t的欧拉序列f(类似于欧拉回路)。

为了方便,把结点k在欧拉序列中第一次出现的序号记为pos(k)。

有了欧拉序列,lca问题可以在线性时间内化为rmq问题:lca(t,u,v)=rmq(b,pos(u),pos(v))。这里rmq返回的是下标而不是值本身。

这个等式不难理解:从u走到v的过程中一定会经过lca(t,u,v),但不会经过lca(t,u,v)的祖先。因此,从u走到v的过程中经过的深度最小的结点就是lca(t,u,v)。

用dfs计算欧拉序列的时间复杂度是o(n),且欧拉序列的长度是2n-1=o(n),所以lca问题可以在o(n)的时间内转化成等规模的rmq问题。

树的动态查询问题1。给定一棵带边权的树,要求支持两种操作:修改某条边的权值和询问树中两点间的距离。

首先把无根树变成有根树,则把一条边u-v(假定u是v的父亲结点)的权值增加d时,以u为根的整个子树的“到根节点的距离”同时增加d。不难发现,一棵子树内的结点对应欧拉序列中的一段连续序列,因此如果用dist[i]表示欧拉序列中第i个结点到根的距离,则修改操作就是dist数组上的“区间增量”,而查询时的距离(u,v)等于dist(u)+dist(v)-2dist(w),其中w=lca(u,v)。这样,只需用一个支持快速区间增量和单点查询的数据结构(例如fenwick树或者线段树)来维护dist数组,就可以在o(log n)的时间内支持两个操作。

轻重路径剖分。给定一棵有根树,对于每个非叶节点u,设u的子树中结点数最多的子树的树根为v,则标记(u,v)为重边,从u出发往下的其它边均为轻边。

根据上面的定义,只需一次dfs就能把一棵树分解成若干重路径(重边组成的路径)和若干轻边。有些资料也把重路径称为树链,因此轻重路径剖分也称树链剖分。

路径剖分最重要的定理如下:若v是u的子结点,(u,v)是轻边,则size(v)<size(u)/2,其中size(u)表示以u为根的子树中的结点总数。

证明并不复杂。由定义,所有非叶结点都有一条重边。假设size(v)>=size(u)/2,那么对于u向下的重边(u,w)来说,size(w)>=size(v)>=size(u)/2,因此size(u)>=1+size(v)+size(w)>=1+size(u),与假设矛盾。

由此可以得到如下重要结论:对于任意非根结点u,在u到根的路径上,轻边和重路径的条数均不超过log2n因为每碰到一条轻边size值就会减半。

树的动态查询问题2。给定一棵带边权的树,要求支持两种操作:修改某条边的权值和询问树中两点之间唯一路径上的最大边权。

首先把无根树变成有根树并且求出路径剖分。任意结点u到其根节点x的简单路径中包含一些轻边和重路径,但这些重路径可能并不是原树中的完整重路径,而是一些“片段”,因此可以在轻边中直接保存边权,而用线段树维护重路径。这样两个操作都不难实现。

修改:轻边直接修改,重边需要在重路径对应的线段树中修改。

查询:设lca(u,v)=p,则只需求出u到其祖先p之间的最大变权maxw(u,p),再用类似的方法求出maxw(v,p),则答案为max{maxw(u,p),maxw(v,p)}。为了求出maxw(u,p),依次访问u到p之间的每条重路径和轻边即可。根据刚才的结论,轻边和重路径的条数均不超过log2n。这样,修改的时间复杂度为o(log n),查询的时间复杂度为o(log2n)。虽然存在时间复杂度更低的方法,但上述方法已经很实用了。

以上是关于树的经典问题和方法的主要内容,如果未能解决你的问题,请参考以下文章

树的dfs序,p1539,其他经典问题,2018/11/08模拟赛T3

经典面试题(十六)--二叉树的镜像

经典面试题二二叉树的递归与非递归遍历(前序中序后序)

(经典)二叉树的层次遍历和快速排序

数据挖掘十大经典算法--CART: 分类与回归树

「经典题目回顾」翻转二叉树!