树链剖分
来源:互联网 发布:v380监控软件安卓版 编辑:程序博客网 时间:2024/06/06 19:49
前言:
树链剖分,就是将树剖成一条条链,然后通过数据结构(如Treap,线段树,树状数组,Splay,LCT或者各种树套树)维护这些链,从而快速完成路径的权的统一修改,增加,求极值等。
其实,以前关于树剖的博客,我已经写过了。。。但由于写得太难看,最后删掉了。。。现在把它补上。
初一参加的GDOI和GDKOI,听了不止两遍的树链剖分(好像都是关于第4题的),可每次都听不懂。那时我的心情是这样的:
这就是树链剖分了。。。
好吧,不说废话了。直接进入主题:
先定义Size值为以该节点为树根的子树的节点个数。
重儿子:是该节点所有儿子中Size值最大的儿子。而与重儿子相连的边就叫重边,其余的就叫轻边了。
如上图,用重边组成一条条重路径。
可以知道,从根节点到某一节点u,经过的轻边和重路径不会超过条。
理由:先证明树链剖分一个重要的性质:
如果有任何一个节点u和其轻儿子v,都有
证明:
反证法:假设;
则对于u的重儿子v1,有:
左边两式相加:
可得:
与Size的定义矛盾,假设不成立,故原结论成立。
有了这个定理,问题不难解决:
如果从根节点走到u,最多经过条轻边,因为每经过一次轻边,Size值至少没了一半。
好了,接下来的问题来了,该如何用数据结构(后以线段树为例)来维护重路径的操作?每一条重路径都建一个线段树?显然不是。我们可以将每一个点(或者边)都给其重新编号,使相邻的重边的编号相邻。那么,只需dfs即可,先dfs重儿子,再dfs轻儿子,然后给上编号。为了确定重儿子,在这之前还要搞一次dfs以确定重儿子。
那么,该如何实现路径的这些操作?使两个点一边靠近它们的LCA,一边进行操作。
1,如果两个点还不在同一条重路径上,对深度较深的点进行操作。
可以从该节点x到重路径的顶端top[x]用线段树进行修改(或查询),并暴力修改(查询)top[x]和fa[top[x]]的这条轻边。x跳到fa[top[x]],并重复该操作。
2,如果两点已在同一条重路径上了,那么用线段树修改(查询)这两个点之间边(或点)。
至此,我们需要用到的数组有:
size[]:以该节点为根节点的子树的节点个数
dep[]:该节点在树中的深度
fa[]:该节点的父亲
son[]:该节点的重儿子
top[]:该节点所在重路径中深度最小的点
tid[]:该点(边)在线段树中的位置。
void dfs1(int u,int p)//第一次Dfs {vis[u] = true;dep[u] = dep[p] + 1;//计算深度 fa[u] = p;//父亲 siz[u] = 1;//初始化Size值 int len = adj[u].size();for(int i=0;i<len;i++){int v = adj[u][i];if((!vis[v]) && (v != fa[u])){dfs1(v,u);siz[u] += siz[v];//计算Size值 if(son[u] == 0) son[u] = v;//先取第一个儿子为重儿子 else if(siz[son[u]] < siz[v]) son[u] = v;//然后去Size值最大的点 }}}void dfs2(int u,int tp)//第二次dfs {vis[u] = true;tim ++;tid[u] = tim;top[u] = tp;//计算top if(son[u]) dfs2(son[u],tp);//先dfs重儿子 int len = adj[u].size();for(int i=0;i<len;i++)//然后dfs其他儿子 {int v = adj[u][i];if((!vis[u]) && (v != fa[u] && v != son[u]))//注意需判断该节点是否不为重儿子 dfs2(v,v);}}
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- 树链剖分
- hpuoj【1216】复习! 复习!【贪心】
- android操作系统
- 利用redis + lua解决抢红包高并发的问题
- 比尔·盖茨:我想与2017届毕业生分享的人生功课
- How to establish a big data platform ?
- 树链剖分
- Error:Could not find com.android.support:appcompat-v7:25.3.1.
- SpringBoot如何添加拦截器
- linux配置静态路由实现路由转发和quagga实现动态路由实验
- git学习(廖雪峰的git教程)笔记 一
- 关于SpannableString的一些用法
- JS 数组 常用操作
- Spring技术内幕——深入解析Spring架构与设计原理(二)AOP
- AssetBundle and the AssetBundle Manager介绍