首页 > 其他分享 >树链剖分学习(复习?)笔记

树链剖分学习(复习?)笔记

时间:2023-08-23 21:24:49浏览次数:39  
标签:son 复习 剖分 int siz top 树链 重链

树链剖分,即树剖。
顾名思义,树链剖分就是将一棵树通过某种方式剖分成若干条链,再利用 \(dfs\) 序,从而将树上的问题转化为序列上的问题。

树剖的方式有不止一种,比如重链剖分、长链剖分。最常用的(大概?)是重链剖分。此处介绍重链剖分。

首先,我们定义一个节点的重儿子为此节点的所有儿子中子树大小最大的一个(如果有多个就任取一个),其他的儿子为轻儿子。我们称这个节点与它的重儿子之间的边为重边,其余边为轻边,若干条重边构成的一条链为重链,并且我们把落单的点也视作重链,于是一棵树就被剖分为了若干条重链。

实现可以用两次 \(dfs\),第一次 \(dfs\) 记录节点的深度 \(dep\)、子树大小 \(siz\) 和重儿子\(son\)。

\(Code:\)

il void dfs1(int x,int father,int depth){
	siz[x]=1,fa[x]=father,dep[x]=depth;
	for(re int i=head[x];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==father)continue;
		dfs1(v,x,depth+1);
		siz[x]+=siz[v];
		if(siz[v]>siz[son[x]])son[x]=v;
	}
}

重头戏:

第二次 \(dfs\),我们对节点重新编号\((id)\),并且我们在搜索的时候优先搜索重儿子。同时我们记录每个节点所在重链的起点 \(top\)。

\(Code:\)

il void dfs2(int x,int top_now){
	id[x]=++idx;
	a[idx]=b[x];
	top[x]=top_now;
	if(!son[x])return;
	dfs2(son[x],top_now);
	for(re int i=head[x];i;i=e[i].nxt){
		int v=e[i].v;
		if(v==fa[x]||v==son[x])continue;
		dfs2(v,v);
	}
}

然后,因为是 \(dfs\) 序,所以同一棵子树上的节点编号 \(id\) 一定连续,又因为我们优先搜索重儿子,所以一条重链上的点编号 \(kid\) 也连续。于是我们就将树上问题转化为序列上的问题。

比如我们要实现单点修改、子树整体修改、路径修改、查询子树和、子树最大值、路径长度、路径上的最大值等等操作,就可以直接在树剖之后用线段树做。

具体来说,因为一棵子树内的编号 \(id\) 连续,所以它一定可以被表示为一段区间,那么我们直接在线段树上操作就好了。即:

update(id[x],id[x]+siz[x]-1)//更新以x为根的子树

对于路径上的操作,我们可以把这条路径剖分成若干条重链(数量在 \(log\) 级别以内,保证了复杂度)。然后将重链转化为区间,在线段树上进行操作。

il int GetSum_on_Path(int x,int y){
	int res=0;
	//一直跳重链直到x和y在同一条重链上
	//此处默认跳x,所以每次令x为深度更大的那个点
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		res+=GetSum(1,1,n,id[top[x]],id[x]);//丢给线段树
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	//因为在同一条重链上了,所以直接进行操作
	res+=GetSum(1,1,n,id[y],id[x]);
	return res;
}

\(update\) \(on\) \(230823:\)

然后就想起来两件事情:

\(1.\)关于时间复杂度

大概就是,每次从重链调到轻链的时候,点数规模至少下降一半?于是可以保证 \(log\) 的复杂度,并且大部分情况下跑不满,常数很小。

懂了,以后写 \(LCA\) 就用树剖了!反正倍增我已经忘记具体实现了

\(2.\)关于边信息转点信息

显然,要保证一一对应的话,直接把每条边的信息继承给它下方,或者说深度更大的一个点就好了。这个在第一次 \(dfs\) 的时候就可以实现,然后就是还有一个细节。呃,不好说,直接看代码吧。

il void update_Path(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update(1,1,n,id[top[x]],id[x],1);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	update(1,1,n,id[y],id[x],1);
	update(1,1,n,id[y],id[y],-1);
}

就是画一下图会发现有个地方是不该管的,把它去掉就ok了。

标签:son,复习,剖分,int,siz,top,树链,重链
From: https://www.cnblogs.com/MrcFrst-LRY/p/17652788.html

相关文章

  • vue复习
    vuevue是什么?它是一个轻量级MVVM框架数据驱动+组件化的前端开发Github超过25K+的star熟,社区完善Vue.js更轻量,gzip后大小只有26K;更易上手,学习曲线平稳形成Vue渐进式框架的核心概念为:组件化,MVVM,响应式,和生命周期vue的优缺点优点1.轻量级Vue作为一款轻量级前端框架,大......
  • 《408操作系统 》复习笔记 ③ 第二章 调度与调度算法
    调度当有一堆任务要处理,由于资源有限,没办法同时处理。需要某种规则来决定处理这些任务的顺序作业作业:一个具体的任务用户向系统提交一个作业=用户让操作系统启动一个程序(来处理一个具体的任务)调度的三个层次高级调度(作业调度)按照某种策略从外存的作业后备队列中挑选......
  • 树链剖分/重链剖分模板
    #include<bits/stdc++.h>usingnamespacestd;intn,m,d,mod,w[200005],wt[200005],e[200005],ne[200005],h[200005],idx=1,t[800005],l[800005],r[800005],tag[800005];intson[200005],id[200005],fa[200005],cnt,dep[200005],siz[200005],top[200005];/*son[]重儿子......
  • 『复习笔记』树链剖分(重链剖分)
    前言(事出必有因)今天模拟赛有一道线段树+LCA的题,考场上码了两个小时,结果pushup错了,结果线段树调完了,发现TLE了,原来是求LCA炸了。。因为我用的倍增(我就是倍增狗你能把我怎么样),但是倍增的一个重要问题就是log都跑满了,但是树剖跑不满log,别问我为什么不用Tarjan,因为这题是在线的不好......
  • SpringBoot复习:(36)国际化
    一、Resources目录下建立一个目录(比如international)来存储资源文件message.properties空的,但不能没有message_zh_CN.propertieshello=您好message_en_us.propertieshello=helloworld二、自动配置类MessageSourceAutoConfiguration常量MESSAGE_SOURCE_BEAN_NAME为messageSourc......
  • SpringBoot复习:(40)@EnableConofigurationProperties注解的用法
    一、配置文件:server.port=9123二、配置类:packagecn.edu.tju.config;importcom.mysql.fabric.Server;importorg.springframework.boot.autoconfigure.web.ServerProperties;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.......
  • SpringBoot复习:(44)MyBatisAutoConfiguration
    可以看到MyBatisAutoConfiguration引入了MyBatisProperties这个属性:MyBatisAutoConfiguration中配置了一个SqlSessionFactoryBean,代码如下:可以配置mybatis-config.xml,需要配置文件里指定:mybatis.config-locatinotallow=classpath:/mybatis-config.xml同样可配置MyBatis的xml......
  • SpringBoot复习:(46)全局的bean懒加载是怎么实现的?
    在application.properties中配置:spring.main.lazy-initialization=true在运行SpringApplication的run方法时,代码如下:其中调用了prepareContext,prepareContext代码如下:当在配置文件中配置了spring.main.lazy-initializatinotallow=true后,SpringApplication实例的this.lazyInitial......
  • SpringBoot复习:(51)默认情况下DataSource是怎么创建出来的,是什么类型的?
    DataSource是通过DataSourceAutoConfiguration创建的,这个类代码如下:可以看到DataSourceAutoConfiguration有个静态内部类PooledDataSourceConfiguration,在这个类上有个@Import注解,导入了DataSourceConfiguration.Hikari这个类,它的代码如下:可以看到,如果没有在配置文件指定spring......
  • SpringBoot复习:(37)自定义ErrorController
    所有接口统一返回的数据格式packagecn.edu.tju.domain;publicclassMyResponse{privateintcode;privateStringmessage;privateStringexception;privateStringstack;publicintgetCode(){returncode;}publicvoidse......