ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树链剖分

2020-07-24 08:31:28  阅读:195  来源: 互联网

标签:重链 剖分 int siz dfs 儿子 树链 节点


#树链剖分

1,将树从x到y结点最短路径上所有节点的值都加上z

这也是个模板题了吧

我们很容易想到,树上差分可以以O(n+m)的优秀复杂度解决这个问题

2,求树从x到y结点最短路径上所有节点的值之和

lca大水题,我们又很容易地想到,dfs O(n)预处理每个节点的dis(即到根节点的最短路径长度)

dis(到根节点最短路径长度)

lca性质:树上两点最短距离=dis(x)+dis(y)-2*dis(lca) O(mlogn+n)

树链剖分 就是对一棵树分成几条链,把树形变为线性,减少处理难度

需要处理的问题:

  • 将树从x到y结点最短路径上所有节点的值都加上z
  • 求树从x到y结点最短路径上所有节点的值之和
  • 将以x为根节点的子树内所有节点值都加上z
  • 求以x为根节点的子树内所有节点值之和

概念://可以先看代码再一一理解

  • 重儿子:对于每一个非叶子节点,它的所有儿子中 儿子数量最多的那一个儿子 为该节点的重儿子

  • 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子

  • 叶子节点没有重儿子也没有轻儿子(因为它没有儿子。。)非叶节点有且只有1个重儿子

  • 重边:连接父亲节点与重儿子的边叫做重边

  • 轻边:剩下的即为轻边

  • 重链:相邻重边连起来的的路径叫重链

  • 轻链:轻边连的路径

  • 对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链

    变量声明:

    \(fa[i]~i的爸爸,d[i]~i的深度,siz[i]i为根的子树节点个数,wson[i]保存重儿子,rk[i]保存当前dfs标号在树中对应节点\)

    \(top[i]当前节点所在链顶端节点,id[i]~dfs执行顺序(剖分后新编号)\)

    两遍dfs

dfs1():

处理出siz和son数组(如果一个点多个儿子子树相等且最大,随便找一个当重儿子)

顺便记录点的父亲和深度,处理fa和d数组,手动模拟一下吧

inline void dfs1(int x,int fa,int deep){
	dep[x] = deep;//标记每个点深度
	fa[x] = fa;
	siz[x] = 1;//标记每个非叶子节点的子树大小,包含他自己
	//int maxson = -1;//记录重儿子个数
	for(int i = head[x];i;i=edge[i].next){
	int y = edge[i].to;
	if(y == fa) continue;
	dfs1(y,x,deep+1);
	siz[x] += siz[y];	//son的siz已被处理,更新fa的siz
	if(siz[y] > siz[wson[x]]) wson[u]=y;//选最大siz
	}
}

dfs2():

连接重链,标记每个点的dfs序,为了用数据结构维护重链,dfs时保证一条重链各个节点dfs序连续

即处理出top,id,rk

void dfs2(int u,int t){//t重链顶端
	top[u] = t;//
	id[u]=cnt++; //标记dfs序
	rk[cnt] = u;//序号cnt对应节点v
	if(!wson[u]) return;
	dfs2(wson[u],t);
	//优先选择进入重儿子来保证一条重链上各个节点dfs序连续
	//一个点和它的重儿子处于一条同一重链,所以重儿子顶端还是t
	for(int i=head[u];i;i=e[i].next){
		int v = e[i].to;
        if(v != wson[u] && v!=fa[u]) dfs2(v,v);//一个点位于链低端,那么它的top必然是它本身
	}
}

为什么是dfs2(v,v)呢,因为当v是重儿子的时候,它不可能为一条链的顶,因为根据重边的定义,一定有一条边连向重儿子,若重儿子为顶,还会有一条边连向它,所以重儿子不会为顶端。

然后统计答案,中间一定需要别的数据结构

例题和代码就不放了,洛谷上有很多

pshttps://www.cnblogs.com/lykkk/p/10183778.html#autoid-3-0-0 这篇文章写的也很好

标签:重链,剖分,int,siz,dfs,儿子,树链,节点
来源: https://www.cnblogs.com/shikeyu/p/13369947.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有