首页 > 其他分享 >[学习笔记]树链剖分(简易版) 及其LCA

[学习笔记]树链剖分(简易版) 及其LCA

时间:2024-09-19 21:24:07浏览次数:3  
标签:chain 剖分 int top 树链 简易版 LCA now 节点

树链剖分

先讲解一下一些基础定义(都是在树上)

  • 重儿子: 一个节点中所有儿子中子树大小最大的一个儿子(每个节点最多有一个重儿子)
  • 轻儿子: 一个节点除重儿子外所有的节点
  • 重链: 若干个重儿子组成的链
  • 链顶: 一条链中深度最小的节点

以下图为例子 (红色连续线段为重链)
红色连续线段为重链
对于节点 1 1 1 来说, 子树大小最大的儿子是 2 2 2 , 2 2 2 最大的是 5 5 5 , 5 5 5的所有儿子子树大小一样大, 随机选一个即可
对于节点 3 3 3 来说, 虽然本身是一个轻儿子, 但是它有重儿子 4 4 4 , 所以也能构成一条重链
由此观之, 所有的点都在某条重链上(重链可能是一个点)

现在, 我们可以通过 d f s dfs dfs 求出以任意节点为根的子树大小, 并且通过全部比较找出每个节点的重儿子.
之后再次 d f s dfs dfs , 把重儿子连成一条又一条链, 记录每个节点所在链的链顶, 等会 L C A LCA LCA 要用

//知道原理就自己写吧, 我的码风一言难尽, 学长写了50行, 我写了270行, 删完之后还剩150行
void dfs(int now,int father){
	for(int x=0;x<g[now].size();x++){
		node to=g[now][x];
		if(to.v==father){
			continue;
		}
		fa[to.v]=now;
		dfs(to.v,now);
		siz[now]+=siz[to.v];
	}
	return;
}

void dfss(int now,int father){
	int num=0,maxn=-1;
	for(int x=0;x<g[now].size();x++){
		node to=g[now][x];
		if(to.v==father){
			continue;
		}
		if(maxn<siz[to.v]){
			maxn=siz[to.v];
			num=to.v;
		}
	}
	for(int x=0;x<g[now].size();x++){
		node to=g[now][x];
		if(to.v==father){
			continue;
		}
		if(to.v==num){
			chain_top[to.v]=chain_top[now];
		}else{
			chain_top[to.v]=to.v;
		}
	}
	for(int x=0;x<g[now].size();x++){
		if(g[now][x].v==father){
			continue;
		}
		dfss(g[now][x].v,now);
	}
	return;
}

现在树剖完了, 就该 L C A LCA LCA 了

树链剖分LCA

有两个节点 A , B A,B A,B ,求它们最近公共祖先
L C A LCA LCA 的大致思想就是不断地往上跳, 直到两个节点到根的路径成包含关系时停止. 但是这个往上跳的过程很费时间, 于是我们可以通过某些判断, 让节点往上跳一条重链的长度(如图)
这棵树是挺大的在这里插入图片描述
假设现在我要求 L C A ( 15 , 19 ) LCA(15,19) LCA(15,19) 以下是具体操作步骤

  • 判断当前两个节点的链顶是不是同一个点
  • 若是, 则输出两个点中深度小的那个
  • 若不是, 就让链顶深度最大的那个点往上跳, 跳到链顶的父亲节点
  • 重复上述过程, 直到判断为是

要是没太明白的话就自己手动模拟以下:

int LCA(int a,int b){
	while(ct[a]!=ct[b]){
		if(dep[chain_top[a]]>=dep[chain_top[b]]){
			a=fa[chain_top[a]];
		}else{
			b=fa[chain_top[b]];
		}
	}
	if(dep[a]<dep[b]){
		return a;
	}else{
		return b;
	}
}

个人认为这个比倍增 L C A LCA LCA 好理解

例题

今天晚上更

标签:chain,剖分,int,top,树链,简易版,LCA,now,节点
From: https://blog.csdn.net/Wangyd_525/article/details/142369355

相关文章

  • wangeditor——cdn引入的形式创建一个简易版编辑器——js技能提升
    昨天同事那边有个需求,就是要实现聊天功能,需要用到一个富文本编辑器,参考如下:上面的这个效果图是博客园的评论输入框最终使用wangEditor编辑器实现的效果如下:只保留了个别的菜单:默认模式的wangEditor编辑器如下:下面直接上代码:解决步骤1:cdn引入head头部标签引入css<......
  • 树链剖分
    由于是在树上搞的ds所以考察数据结构本身性质偏多,需大力注重细节。思想考虑将一颗树的链划分成若干个区间进行维护。这种划分方式叫做剖分。约束一颗有根树(有时要求换根但不是真正换根)每个点恰好包含在一条剖出的链中(若被多条链同时包含则需要同时维护多条链,修改多余......
  • Android中Fragment的最佳实践—简易版的新闻应用
    文章目录Android中Fragment的最佳实践—简易版的新闻应用app/build.gradle当中添加依赖库新建新闻实体类News新建布局文件news_content_frag.xml新建NewsContentFragment类单页模式需新建NewsContentActivity新建news_title_frag.xml新建news_item.xml新建NewsTitleFragm......
  • 树链剖分
    原理:将一棵树剖分成一条条的链,从而降低时间复杂度首先会一个线段树,书完成剖分后,用来维护每一条的信息。#include<bits/stdc++.h>typedefintintt;#defineintlonglong#definelck<<1#definerck<<1|1constintM=2e6+10;usingnamespacestd;intn,m,ans......
  • 学生管理系统(简易版)
    1.导言学习动态内存管理、与缓冲相关的知识,以及文件管理之后,我便制作了这个简易版的学生管理系统。其中缓冲部分你可能觉得多余(我也这么认为),但为了巩固缓冲的知识我还是加了上去。因此带来的阅读不便,还请见谅!最后希望各位客官指正错误,提出建议。 2.正文1.菜单打印voidmen......
  • 树链剖分
    树链剖分的思想及能解决的问题树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。具体来说,将整棵树剖分为若干条链,使它组合成线性结构,然后用其他的数据结构维护信息。树链剖分(树剖/链剖)有多种形式,如重链剖分,长链剖分和用于Link/cutTree的剖分(有时被称作「实链剖......
  • #8. 「模板」树链剖分
    题目传送门:#8.「模板」树链剖分、前置知识重链:重链(HeavyPath)是指树链剖分中的一条主要的路径,该路径上的节点数量较多,相邻节点之间的距离较近。轻链(LightPath)是指树链剖分中的其他路径,相邻节点之间的距离较远。LCA:最近公共祖先分析上树状数组首先,我们需要定义一个......
  • 重链剖分
    思想我先给出一些定义:定义一个结点的重子节点为其子节点中子树节点数最大的子节点,如有多个,随便取一个作为重儿子,如果没有子节点,就没有重儿子。定义一个结点的轻子节点为其除重子节点外的子节点。从这个节点到重子节点的边为重边,到其他子节点的边为轻边。由重边首位相连的链......
  • 算法总结-树链剖分
    算法总结-树链剖分概念重儿子(红点):父节点\(f\)的子节点中子树大小最大的儿子。轻儿子(蓝点):父节点\(f\)的子节点中除重儿子以外的节点。重链(橙圈框出的链):链顶为轻儿子,由重儿子组成的链。重链剖分用处:将树上任意一条路径划分成不超过\(\log{n}\)条连续的链(如实......
  • 自制最简易版vue.js
    classMyVue{constructor(options){this.$el=document.querySelector(options.el)this.$data=options.datathis.$methods=options.methodsthis.init()this.compile(this.$el)}compile(node){letthat=thisnode.chi......