首页 > 其他分享 >树链剖分学习笔记

树链剖分学习笔记

时间:2024-02-07 23:34:59浏览次数:31  
标签:重链 剖分 int siz 笔记 son dfs 树链 节点

树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、BST、SPLAY、线段树等)来维护每一条链。
——百度百科

重链剖分

概念 1 重儿子

一个父节点的所有儿子中,子树节点最大(siz 最大)的节点。

记为 son[u]=v

概念2 轻儿子

父节点所有儿子中,除过重儿子的所有节点。

概念3 重边

由父亲节点和重儿子连接成的边。

概念4 轻边

由父亲节点和轻儿子连接成的边。

概念5 重链

由多条重边连成的链。

概念5 轻边

由多条轻边连成的链。

实现思路

  1. 对于一个节点先找出它所在的子树大小,同时我们可以得到它的所有子节点的子树大小 siz[v],这样我们可以得到此节点的重儿子。

例如,点 1 的三个儿子分别是 2,3,4。
2 所在的子树大小为 5,
3 所在的子树大小为 2,
4 所在的子树大小为 6,
那么 1 的重儿子就是 4。

  1. dfs 的过程中顺便记录节点 u 的父亲 f[u],从根节点的深度 dep[u]等。

  2. 再来一遍 dfs,连接重链,标记每个节点的 dfs 序,处理出每个节点所在重链的顶点 top[u]和节点编号 id[u]

代码实现

第一遍 dfs

作用主要是找出每个节点的深度重儿子

int son[500010],deep[500101],f[500101];
int siz[500010];
//son:重儿子
//deep:节点深度
//f:节点的父节点 
void dfs1(int u,int fa)
{
	f[u]=fa;
	deep[u]=deep[fa]+1;
	siz[u]=1;
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==fa)continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])
		son[u]=v;
	}
}

第二遍 dfs

作用主要是求出每条重链的顶点和节点的 dfs 序。

//rk:节点编号 
//id:dfn序
//top:重链顶端 
void dfs2(int u,int t)
{

	top[u]=t;
	if(son[u])dfs2(son[u],t);
	id[u]=++cnt;
	rk[cnt]=u;
	for(int i=head[u];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==son[u]||v==f[u])continue;
		dfs2(v,v);
	}
}

这样就完成了树链剖分的基础操作(链式前向星存图)。

标签:重链,剖分,int,siz,笔记,son,dfs,树链,节点
From: https://www.cnblogs.com/ccjjxx/p/18011471

相关文章

  • 【CPL-2023】W14笔记-程序结果、预处理与I/O
    有趣的预编译编写大型程序头文件:变量的声明,函数的声明,宏的定义,预编译指令include库函数include<xx.h>找库函数的路径include自己的头文件include"xx.h",先找当前目录gcc--verbosemain.cgcc-I.include当前目录头文件的重复包含标准头文件结构#ifndef......
  • 洛谷P3455 笔记
    传送门又是一道看了tj的题。题意\(t\)次询问,每次询问给定\(n\),\(m\),\(k\),求\(\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=k]\)。\(1\let\le5\times10^4\),\(1\lek\len\),\(m\le5\times10^4\)正文把\(k\)扔到上界去,记原式变为\(\sum_{i=1}^{\lfloor\frac{n}{k}......
  • 2024/2/7学习进度笔记
    为什么要用非线性函数要解释这个问题,可以反过来思考一下,为什么激活函数不能使用线性函数。如果使用线性函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合。加深神经网络的层数就没有什么意义了。线性函数的问题在于不管加深层数到多少,总是存在......
  • Go语言精进之路读书笔记第19条——理解Go语言表达式的求值顺序
    第19条了解Go语言控制语句惯用法及使用注意事项19.1使用if控制语句时应遵循"快乐路径"原则当出现错误时,快速返回;成功逻辑不要嵌入if-else语句中;"快乐路径"当执行逻辑中代码布局上始终靠左,这样读者可以一眼看到该函数当正常逻辑流程;"快乐路径"的返回值一般在函数最后一行。......
  • Go语言精进之路读书笔记第17条——理解Go语言表达式的求值顺序
    Go语言表达式支持在同一行声明和初始化多个变量支持在同一行对多个变量进行赋值(不同类型也可以)vara,b,c=5,"hello",3.45a,b,c:=5,"hello",3.45a,b,c=5,"hello",3.45RobPike练习题(规则见17.3赋值语句的求值)n0,n1=n0+n1,n0或者n0,n1=op(......
  • 领域驱动设计(Domain-Driven Design,简称DDD)【简介 个人学习笔记】
    找到了第1篇资料:领域驱动设计详解:是什么、为什么、怎么做?-知乎找到了第2篇资料:领域驱动架构(DDD)建模中的模型到底是什么?-知乎找到了第3篇资料:一文看懂DDD领域驱动设计-知乎找到了第4篇资料:什么是DDD(领域驱动设计)?这是我见过最容易理解的...找到了第5篇资料:领......
  • Go语言精进之路读书笔记第18条——理解Go语言代码块与作用域
    18.1Go代码块与作用域简介Go规范定义了如下几种隐式代码块。宇宙代(Universe)码块:所有Go源码都在该隐式代码块中,就相当于所有Go代码等最外层都存在一对大括号。包代码块:每个包都有一个包代码块,其中放置着该包都所有Go源码文件夹代码块:每个文件都有一个文件代码块,其中包含着该......
  • Go语言精进之路读书笔记第15条——了解string实现原理并高效使用
    15.1Go语言的字符串类型在Go语言中,无论是字符串常量、字符串变量还是代码中出现的字符串字面量,它们的类型都被统一设置为string特点string类型的数据是不可变的对string进行切片化后,Go编译器会为切片变量重新分配底层存储而不是共用string的底层存储string的底层的数据存......
  • Go语言精进之路读书笔记第16条——理解Go语言的包导入
    Go编译速度快的原因主要体现在以下三方面:Go要求每个源文件在开头处显式地列出所有依赖的包导入,这样Go编译器不必读取和处理整个文件就可以确定其依赖的包列表。Go要求包之间不能存在循环依赖。这样一个包的依赖关系便形成了一张有向无环图。由于无环,包可以被单独编译,也可以并行......
  • Django知识笔记1
    本文从分析现在流行的前后端分离Web应用模式说起,然后介绍如何设计RESTAPI,通过使用Django来实现一个RESTAPI为例,明确后端开发RESTAPI要做的最核心工作,然后介绍DjangoRESTframework能帮助我们简化开发RESTAPI的工作。Web应用模式在开发Web应用中,有两种应用模式:前后端不分离......