博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树链剖分总结笔记
阅读量:4452 次
发布时间:2019-06-07

本文共 1951 字,大约阅读时间需要 6 分钟。

之前写过关于树链剖分学习的相关笔记,那个笔记的内容就比较粗略,为了加深树链剖分的学习,在这里进行一次尽量完整地总结,静下心来,进行一次完整的学习

树链剖分本质上是利用两次dfs进行树上搜索来保存树上信息,利用这些信息从而可以让线段树或者树状数组这样区间操作很快的数据结构发挥作用!

为什么?

我们首先需要从树链剖分的思想开始入手:

树链剖分是将树结构转化为一个序列区间

为什么?

区间容易维护

怎么做?

就是利用dfs进行转化

 

那么我们的重点就是如何进行dfs,如何利用dfs保存的信息来建树。

 

在此之前,我们首先要开始探究树链剖分的定义:

fa(x)表示x在树上的父亲

siz(x)表示x子树的大小(节点数量)

son(x)表示x的重儿子(就是x的儿子中siz最大的子节点)

dep(x)表示x节点的深度

top(x)x所在链上的顶部端点

tid(x)和rnk(x)相互映射

tid(x)相当于树上节点->树链剖分成序列点序

rnk(x)相当于树列剖分的点序->树上节点

这里加一条就是再边权维护的时候,要将边映射到点上,进行剖分

就利用eid(x)->该边的端点

 

我们知道这些定义的变量之后,就可以去进行两次dfs了

第一次dfs目的是为了求fa、siz、son、dep这四个变量,只是求出来树上的每一个节点的信息

1 int dfs1(int u, int f) { 2     dep[u] = dep[f] + 1, siz[u] = 1, son[u] = 0, fa[u] = f; 3     for (int i = head[u]; i; i = next[i]) { 4         int v = ver[i]; 5         if (v == f) continue; 6         siz[u] += dfs1(v, u); 7         eid[(i-1) / 2 + 1] = v;//维护边权需要对边进行映射 8         if (siz[v] > siz[son[u]]) son[u] = v; 9     }10     return siz[u];11 }

第二次dfs目的是为了求剩下的变量

1 void dfs2(int u, int tp) { 2     top[u] = tp, tid[u] = ++pos, rnk[pos] = u; 3     if (!son[u]) return; 4     dfs2(son[u], tp); 5     for (int i = head[u]; i; i = next[i]) { 6         int v = ver[i]; 7         if (v == fa[u] || v == son[u]) continue; 8         dfs2(v, v); 9     }10 }

注意入口

1 dfs1(1,0);2 dfs2(1,1);

接下来想要建立维护变量的数据结构实际上就是对于剖分后的区间进行映射到你要维护的区间上就好了

 

关于如何求解路径上的一些答案

1 int linkquery(int u, int v) { 2     int ans = 0; 3     while (top[u] != top[v]) { 4         if (dep[top[u]] < dep[top[v]]) std::swap(u, v); 5         ans += ask(1, tid[top[u]], tid[u]); 6         u = fa[top[u]]; 7     } 8     if (u == v) return ans; 9     if (tid[v] < tid[u]) std::swap(u, v);10     ans += ask(1, tid[u] + 1, tid[v]);11     return ans;12 }

以上总结代码依赖于:

 

步骤与代码:

  1. dfs1(当前节点,当前节点父亲节点)
  2. dfs2(当前节点,端点)
  3. 构建数据结构
  4. 通过不断的跳转端点,从而query出答案来

一些细节:

  • 因为深度取决于父亲节点,可以直接由父亲节点的dep推出
  • son可以为0,这样不需要修改
  • siz节点包括自身(子树包括自身)
  • dfs2优先处理重儿子,让链尽量长,这样子链条总数为O(logN)
  • 点权维护要有端点处理,边权因为映射到u->v的v上,所以少了一个点,也就是不维护端点
  • 优先跳转深度浅的

转载于:https://www.cnblogs.com/rign/p/10800697.html

你可能感兴趣的文章
OSX: 10.9的SMB网络共享连接可能破坏其权限设置
查看>>
连接不上sql server服务器的解决方案
查看>>
《鬼谷子的局5》—— 读后总结
查看>>
记录安装oracle的那些事(二)之双系统安装
查看>>
c3po数据库连接池中取出连接
查看>>
bootstrap-table 分页
查看>>
使用本机IP调试web项目
查看>>
【bzoj1082】栅栏[SCOI2005]
查看>>
day18 Java学习(Map集合)
查看>>
Integer与int的区别
查看>>
hdu 1087
查看>>
LazyMan的Promise解法
查看>>
lua语言三则特性
查看>>
asp.net的Nelocity模板引擎
查看>>
fis webpack 原理对比
查看>>
22 广播的发送
查看>>
Linux 创建用户 限制SFTP用户只能访问某个目录
查看>>
正则表达式的学习笔记
查看>>
android图片特效处理之图片叠加
查看>>
结束贪心hdu 2491 Priest John's Busiest Day
查看>>