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

树链剖分,树剖

时间:2022-09-03 11:44:11浏览次数:57  
标签:剖分 树剖 int top 树链 dep dfn 节点

树剖是把一棵树拆成一堆链,\(O(logn)\)地跳链,用一些数据结构维护每条链,从而实现增加1k代码而降低复杂度到\(O(log^2n)\)的效果。

树链剖分大概分三种:长链剖分,实链剖分和重链剖分。一般说树剖就是重链剖分。

如何把树拆成链?我们定义一个节点的重子节点是它子树最大的儿子,其余的为轻子节点。于是我们把一个节点与它的所有重儿子连成链。

重子节点所组成的链叫重链。显然,一条链的起点一定是轻子节点。于是我们成功把树剖了。

接下来是如何维护这些链的问题。我们树上套数据结构常用dfs序。这个也是,只要我们求dfs序的时候从重子节点开始搜索,就可以保证重链上的dfs序是连续的。

//找重儿子  
void dfs1(int x,int f,int d){
	fa[x]=f;dep[x]=d;size[x]=1;son[x]=0;//我们需要存每个节点的重儿子和父亲 
	int maxsize=0;
	for(int i=head[x];i;i=edge[i].next){
		if(!dep[edge[i].v]){
			dfs1(edge[i].v,x,d+1);
			size[x]+=size[edge[i].v];
			if(maxsize<size[edge[i].v]){
				maxsize=size[edge[i].v];
				son[x]=edge[i].v;//dfs找重儿子 
			}
		}
	}
}
//连重链  
void dfs2(int x,int f){
	dfn[x]=++num;top[x]=f;rnk[num]=x;
	wei[num]=val[x];
	if(son[x])dfs2(son[x],f);//每次搜索优先从重儿子开始 保证了重链上的dfs序连续 
	for(int i=head[x];i;i=edge[i].next){
		if(edge[i].v!=son[x]&&edge[i].v!=fa[x])dfs2(edge[i].v,edge[i].v);
	}
}
dfs1(1,0,1);dfs2(1,0);build(1,1,n);

然后是树上的修改与查询。(其实差不太多)

关于修改,我们每次大概可以找到树上要修改的链上的lca。于是我们每次修改该点所在的一条链然后往上面一条链上跳,一直跳到同一条链。具体见注释。

void change(int x,int y,int val){
	while(top[x]!=top[y]){//不在同一条链上 
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update(1,dfn[top[x]],dfn[x],val);//修改当前链 
		x=fa[top[x]];//往上跳 
	}
	if(dep[x]>dep[y])swap(x,y);
	update(1,dfn[x],dfn[y],val);//在同一条链上 直接修改 
}
int querysum(int x,int y){
	int num=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		num+=query(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	num+=query(1,dfn[x],dfn[y]);
	return num;
}

然后对子树整体的操作,我们之前dfs序的时候整棵子树的dfs序都连续,所以直接改就行。

query(1,dfn[x],dfn[x]+size[x]-1)

标签:剖分,树剖,int,top,树链,dep,dfn,节点
From: https://www.cnblogs.com/gtm1514/p/16652255.html

相关文章

  • 长链剖分以及对剖分的理解
    https://www.cnblogs.com/maoyiting/p/14178833.html#/cnblog/works/article/14178833目前接触到的重链剖分,长链剖分,实链剖分里面都有一些共同的性质吧!比如,每个点仅存在......
  • CF609E Minimum spanning tree for each edge 【最小生成树+树链剖分】
    CF609EMinimumspanningtreeforeachedge题目描述给你\(n\)个点,\(m\)条边,如果对于一个最小生成树中要求必须包括第\(i(1\lei\lem)\)条边,那么最小生成树的......
  • 树链剖分
    一.写在文前前置芝士:线段树,另外可能学了LCA会更好理解一点树链剖分的板子就是基于线段树哒!不会的读者先去学习它再来看下面的部分叭!qwq先阅读下板子题叭!二.一些有用的......
  • 基础长链剖分
    基础长链剖分基本上整个互联网上长链剖分都是使用CF1009F和树上\(k\)级祖先两题。本篇也无法避免qwq,因为这两题确实经典。定义定义重儿子表示其子节点中子树深度......
  • LCA 相关 && 树链剖分
    LCA基本定义:最近公共祖先简称LCA(LowestCommonAncestor)。两个结点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。简单来讲,就是两个点到根的路径上,深度最深......