首页 > 其他分享 >开拓计划4 - 二叉树与并查集

开拓计划4 - 二叉树与并查集

时间:2024-12-14 10:10:47浏览次数:3  
标签:递归 int NKOJ 查集 开拓 二叉树 节点

开拓计划4 - 二叉树与并查集

二叉树

二叉树的概念

  • Q:什么是树?
  • A:一种有 \(n\) 个节点最多有 \(n-1\) 条边的图。
  • Q:什么是二叉树?
  • A:每个节点都最多只有两个子节点的树。

二叉树和递归

  • Q:二叉树和递归有什么关系?

  • A:在执行递归的时候总是会自己调用自己,每一次调用都会产生新的一层,新的这几个需要执行的函数就成为了当前节点的子节点,一颗递归树就能画出来。

NKOJ 4376 遍历二叉树1

思路:二叉树的入门应用。

实现方法

  • 先序遍历是根左右,中序遍历是左根右,后序遍历是左右根。
  • 按照顺序,执行输出,向左递归,向右递归。

注意事项

  1. 在遍历二叉树时,注意是从根节点开始,不是从 \(1\) 号结点开始。

NKOJ 3909 遍历二叉树2

思路:二叉树的简单应用。

实现方法

  • 用先序确定根节点,再通过中序,确定哪些是左子树,那些是右子树。
  • 左右分别递归下去,要求后续,递归写完再输出。

注意事项

  1. 注意递归时不要把自己也递归了。

NKOJ 8599 无根树

思路:二叉树的简单应用。

实现方法

  • 简单地从根节点开始递归遍历二叉树,每深入一层记录层数的 k 就 \(+1\) 每次取 k 的最大值。

注意事项

  1. 一定不要用邻接矩阵存储二叉树,会 TLE

并查集

对并查集的一些看法

  • 并查集虽然是和集合有关,但是并没有遵循数学中对集合的严格规定,表达的更多是一种节点与节点之间的关系。

并查集的原理

  • Q:并查集的使用场景和理论基础是什么?

  • A:在二叉树中,每个节点都有自己的父节点(可以认为根节点的父节点是它自己),如果题目给了节点之间的关系(不一定是从属关系),就可以把两个节点放在同一棵二叉树里,如果要找两个节点在不在同一个集合,只需要找它们的父亲节点是否相同。

  • Q:并查集如何存储?

  • A:由于并查集需要经常找父亲,所以我们在数组中存储每个节点的父节点编号,初始时每个节点的父节点是它自己。

  • Q:并查集如何查找?

  • A:不断地向上递归,只要当前节点有父就继续想上找父节点,直到找到根节点就返回。

  • Q:并查集如何合并?

  • A:有两个节点要合并,就先判断是否在同一个集合中,如果不在就将一个的根节点变成另一个的根节点。

并查集的路径压缩

  • Q:为什么要路径压缩?
  • A:当并查集的所有节点成一条链状的时候,向上查找的时间复杂度会达到 \(O_n\) 我们无法接受,采用路径压缩优化。
  • Q:路径压缩怎么写?
  • A:当我要向上找一个节点的父节点只要找到祖宗,就将它的父节点直接设为祖宗节点(有点像一个城市要向中央汇报工作,要先向省级政府汇报,但如果是直辖市就可以直接跳过省级政府)。

并查集模板代码

int fa[20005];
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);//路径压缩
}
//核心找父节点
void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy) fa[fx]=fy;
}
bool same(int x,int y){
	return find(x)==find(y);
}
void init(){
	for(int i=1;i<=n;i++) fa[i]=i;
}

NKOJ 1205 亲戚

思路:并查集模板题

NKOJ 3197 岛屿

思路:并查集模板题

NKOJ 5614 加点

思路:可以直接到的加一个并查集,一共有几个并查集

NKOJ 2081 学外语

思路:会同一种语言的员工加一个并查集,一共有几个并查集

NKOJ 5681 交换排列

思路:一道看着像思维题的并查集

实现方法

  • 能交换的两个点之间连一条边,计算有多少个点和它应该在的位置不在同一个集合中。

带权并查集

带权并查集的原理

  • Q:带权并查集的原理是什么?
  • A:带权并查集,是在常规的并查集的基础上给每一个点都加上了权值,并在路径压缩和合并的时候更新。给每一个点都带上权值,大大提升了并查集的作用范围。
  • Q:权值可以带什么?
  • A:一般可以带区间和、区间和的奇偶性、点与点之间的关系 etc.

带权并查集的模板代码

以求区间和为例

void getf(int x){
	if(f[x]!=x){
		int t=f[x];
		f[x]=getf(f[x]);
		val[x]+=val[t];//更新权值
	}
	return f[x];
}
void merge(int x,int y,int v){
	int fx=getf(x),fy=getf(y);
	if(fx==fy) return;
	f[fx]=fy;
	val[fx]=val[y]-val[x]+v;
}

时光倒流思想

  • Q:什么是时光倒流思想?
  • A:时光倒流思想,是将所有的输入数据输入进来,发现用题目告诉我们的方法直接用数据结构模拟难以实现(如并查集难以实现删边),将数据倒序操作变成原来的相反操作(如并查集的删边变成加边)。

NKOJ 5682 果老师炸桥

题意

  • 对于一个无向图,每次删一条边,求每次删完后有多少对点无法互相到达。

思路:带权并查集+时光倒流

实现方法

  • 每次合并时将集合大小一同进行合并,每删一次边就会有那两个集合内的点两两不可达。
  • 由于可撤销并查集,代码多时间高,于是采用时光倒流和简单带权并查集。

NKOJ 2281 方块游戏

思路:带权并查集

实现方法

  • 用两个数组分别记录当前方块堆的高度,和距离根节点的距离,只有这样才能使用路径压缩。
  • 每次在 getf 函数中更新距离根节点的距离,在 merge 函数中更新 dishgt 。把距离根节点的距离加上堆在它顶上那一堆原来的高度,高度也加上那一堆的高度,把被移动后的高度归零。
  • 每次查询的时候要先跑一遍 getf ,类似于线段树的下放懒标记的操作。

标签:递归,int,NKOJ,查集,开拓,二叉树,节点
From: https://www.cnblogs.com/hsr-ray-blog/p/18606422

相关文章

  • NKOJ 1209 并查集【NOI2001 Day1 T3】食物链
    NKOJ1209并查集【NOI2001Day1T3】食物链思路:带权/种类并查集方法一实现方法用带权并查集带的权值是边权,不是点权,用来表示两点间的关系,但为了方便记录还是用点权,每个点记录到根节点的权值。在getf函数中注意更新是到根节点之间的权值,用\(val_x=(val_x+val_{fa_x})\bm......
  • NKOJ 2107 【并查集】可爱的猴子
    NKOJ2107【并查集】可爱的猴子思路:普通并查集+图的遍历更新答案实现方法首先使用时光倒流思想解决删边的问题。注意提前把没有删过的边提前建上。接着用一个图记录猴子之间的拉手关系,每次要更新答案时都遍历与当前节点连着的节点将其答案更新,只有在\(1\)号节点与当前节......
  • 开拓计划1 - 栈与队列
    开拓计划1-栈与队列栈与队列的概念及作用栈的概念Q:什么是栈?A:栈是一种后进先出(BIFO)的数据结构。栈的作用Q:栈有什么作用?A:只要满足栈的定义的场景都可以使用栈。eg:括号匹配,火车进站etc.计算后缀表达式时也会使用。队列的概念Q:什么是队列?A:队列是一种先进先......
  • 代码随想录训练营第十七天| 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 9
    654.最大二叉树  题目链接/文章讲解:代码随想录视频讲解:又是构造二叉树,又有很多坑!|LeetCode:654.最大二叉树_哔哩哔哩_bilibili创建一个根节点,其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组......
  • 代码随想录训练营第十六天| 513. 找树左下角的值 112. 路径总和 106.从中序与后序遍历
    513.找树左下角的值 题目链接:513.找树左下角的值-力扣(LeetCode)讲解链接:代码随想录 求最后一行最后一个左子节点的值就是求二叉树深度最大的叶子节点递归:确定递归函数的参数和返回值参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。这里......
  • XDOJ 735 最小生成树 (Kruskal+并查集)
    标题最小生成树时间限制2S内存限制10000Kb问题描述:用克鲁斯卡尔(Kruskal)算法求无向网的最小生成树。输入:输入数据第一行为两个正整数n(1<n<=30)和m(1<m<100),分别表示顶点数和边数。后面紧跟m行数据,每行数据是一条边的信息,包括三个数字,分别表示该边的两个顶点和边上的权值......
  • 每日一刷——二叉树的构建——12.12
    第一题:最大二叉树题目描述:654.最大二叉树-力扣(LeetCode)我的想法:我感觉这个题目最开始大家都能想到的暴力做法就是遍历找到数组中的最大值,然后再遍历一遍,把在它左边的依次找到最大值,但是emmm,感觉效率很低,时间上肯定过不了然后其实我会觉得这个题目跟大根堆和小根堆有......
  • 数字组合转字母&删除二叉树节点&字符串相乘&打家劫舍ii&无序数组第k大 &无序数组前k大
    一、数字串转换为字符串1-26个数字分别代表26个字符(A-z)输入"12326〞就可以拆分为【1,2,3,2,6】、(12,3,2,6].[1,23,2,6]【1,23,26】、【12,3,26】等,将每种组合转成成对应字母输出,输出所有可能的结果返回所有可能的转换结果//将数字串转换成字母串//将数字串转换成字母......
  • 每日一刷——二叉树——12.09
    第一题:二叉树的层序遍历题目描述:102.二叉树的层序遍历-力扣(LeetCode)我的思路:拿到这个题目,我首先想到的是利用队列来模拟,给我二叉树的根节点,然后我来返回每一层的各个节点,但是为啥我甚至觉得这个题目给的输入就是按照层序遍历来给的呢??然后感觉还有一个点就是咋返回成几......
  • 并查集模板(map保存负数下标)
    classSolution{unordered_map<int,int>fa,rank;voidinit(unordered_set&set){for(constauto&num:set){fa[num]=num;rank[num]=1;}}intfinds(intx){if(x!=fa[x]){fa[x]=finds(fa[x]);}returnfa[x];}voidunions(intx,inty){introotx=f......