其他分享
首页 > 其他分享> > 树链剖分

树链剖分

作者:互联网

#树链剖分

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)

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

需要处理的问题:

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

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