我理解的树链剖分就是将一棵树剖分成若干条链,然后利用数据结构取维护每一条链,复杂度为log(n)
---------------------------------树链剖分对轻重边的划分-------------------------------------------------------------------
定义size(x)为以x为根的子树的节点数.
令v为u的儿子中size最大的节点,那么(u,v)就是重边,其余边为轻边.
那么如此划分,可以得到两条性质:1.轻边(u,v)中,size(v) <= size(u)/2.
因为轻边所连的儿子的size一定不是最大的,所以它最少有一个比它大的兄弟,所以该条性质成立
2.从根到某一点的路径上,不超过log(n)条轻边和不超过log(n)条重路径
因为只有当前节点的儿子数不少于2,才可能出现轻边,出现轻边轻边,才可能出现新的重链,因为二叉树的最大深度logn,所以轻边的数量不可能超过这个深度.
------------------------------算法流程------------------------------------------------------------------------------------------
两次dfs: 1.第一次dfs找出所有的重边并将重边标记
2.dfs链接重边形成重链.具体过程:以根节点为起点,沿着重边向下拓展,拉成重链,不在当前重链上的节点,都以该节点为起点向下重新拉一条重链
每条重链相当于一段区间
剖分过程如下,比较容易理解:
#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 100007
using namespace std;
int siz[MAX]; // 用来保存以x为根的子树的节点个数
int top[MAX];//用来保存当前节点所在链的顶端节点
int son[MAX]; //用来保存重儿子
int fa[MAX]; //用来保存当前节点的父亲
int dep[MAX];//用来保存当前节点的深度
int tid[MAX];//用来保存一棵树中剖分后的新编号
int rank[MAX];//tid的反函数
int tim = 0;
int head[MAX];
struct
{
int v,next;
}e[MAX];
//第一次dfs标记重边
void dfs1 ( int u , int father , int d ) //三个参数分别是当前节点u,当前节点的父亲father,当前的深度d
{
dep[u] = d; fa[u] = father ; siz[u] = 1;
for ( int i = head[u] ; ~i ; i = e[i].next )
{
int v =e[i].v;
if ( v == father ) continue;
dfs1 ( v , u , d+1 );
siz[u] += siz[v];
if ( son[u] == -1 || siz[v] > siz[son[u]] ) son[u] = v ;
}
}
//第二次dfs:连重边成重链
void dfs2 ( int u , int tp )
{
top[u] = tp; tid[u] = ++tim;
rank[tid[u]] = u;
if ( son[u] == -1 ) return;//当前节点为叶节点
dfs2 ( son[u] , tp );
for ( int i = head[u] ; ~i ; i = e[i].next )
{
int v = e[i].v;
if ( v == son[v] || v == fa[u] ) continue;
dfs2 ( v , v );
}
}
int main ( )
{
}
然后就是讲为什么这么剖分?剖分完后,每条重链相当于一段区间,可以用数据结构去维护.
把所有重链首尾相接,放到同一个数据结构中,然后维护这一整体即可.
------------------------------修改操作-------------------------------------------------------------------------------
1.最简单的单点修改
直接根据节点新的标号在数据结构中修改即可
2.整体修改点u到点v的路径上的权值
1)如果u和v在同一条重链上,直接用数据结构修改tid[u]至tid[v]间的值.
2)如果u和v不在同一条重链上,一边进行修改,一边将u和v往同一条重链上靠,然后就转化为了情况1.
a)若fa[top[u]]与v在同一条重链上,说明两条重链之间有一条轻边相连,那么直接修改u到top[u]间各权值,然后u跳至fa[top[u]],转化为情况1
b)若u向上经过若干条重链和轻边与v在同一条重链上,不断修改u和top[u]间的各权值,再将u跳转至fa[top[u]],直至u和v在同意条重链上
c)若u和v都是向上经过若干条重链和轻边,到达同一条重链.每次在点u和点v中,选取dep[top[x]]中较大的x,修改x与top[x]间的各权值,再跳至fa[top[x]],直到u和v在同一条重链上.