【算法】并查集,前缀和数组,差分数组(学习记录)

今天主要学习并查集,前缀和数组和差分数组,写题的同时巩固动态规划。

并查集

我看了一篇关于并查集的博客,写的特别好,通过这篇博客理解了并查集,所以借用这篇博客中提到一些概念来做知识的复习总结。

(博客指路:【算法与数据结构】—— 并查集-优快云博客

并查集解题的几个关键点:根节点合并查询

拿一道模版题来解释:

解这道题,我们需要有判断两个数是否在同一个集合的操作,以及合并两个集合的操作。

判断两个数是否在同一个集合的操作

1. 判断是否在同一个集合只需要看是否都拥有同一个根节点。

2. 既然要判断,就必须要找一下两个数的根节点是啥,这里就用到 find( ) 函数。同时要注意为了避免超时,要在 find( ) 函数中做一个路径压缩

路径压缩可以用递归完成,下面给出模版代码(解释在代码注释中):

//这里优化find函数,实现路径压缩
int find(int a) {
	if (pre[a] == a) {
		return a;
	}
	return pre[a] = find(pre[a]);//理解这一步,是将所有路过的节点的直接上级改为根节点。同时返回所需要的根节点
}

合并两个集合

这里就是将两个集合的根节点统一一下。例如 : pre[ x ] = y,pre[ m ] = n (这里的意思可以理解为,x的根节点为y,m的根节点为n)要合并只需要从y和n中选任意一个根节点当做合并后的根节点即可,例如将y当做合并后合集的根节点,就写成 pre[ m ] = y  

给出模版代码:

if (z == 1) {
//中间为具体操作
	int fx = find(x);
	int fy = find(y);
//如果两个集合的根节点不一样的话,就需要合并集合操作
	if (fx != fy) {
		pre[fx] = fy;
	}
}

有了以上两个核心操作之后,代码基本就没问题了。

判断两个是否在同一个集合,只需要用 find( ) 函数找一下根节点,判断两个根节点是否相同就行。

下面给出完整代码:

#include<stdio.h>

//这里优化find函数,实现路径压缩
int find(int a) {
	if (pre[a] == a) {
		return a;
	}
	return pre[a] = find(pre[a]);//理解这一步,是将所有路过的节点的直接上级改为根节点。同时返回所需要的根节点
}

int pre[200000];//这个数组其实就是涵盖了自己和上级的内容
int main() {
	int N = 0;
	int M = 0;
	int x, y, z;
	scanf("%d%d", &N, &M);
	
	//在还没有任何合并操作前,自己就是自己的教主(根节点)
	for (int i = 1; i <= N; i++) {
		pre[i] = i;
	}
	while (M) {
		scanf("%d%d%d", &z, &x, &y);
		//合并操作(找到教主,合并一下)
		if (z == 1) {
			int fx = find(x);
			int fy = find(y);
			if (fx != fy) {
				pre[fx] = fy;
			}
		}
		else if (z == 2) {
			if (find(x) == find(y)) {
				printf("Y\n");
			}
			else {
				printf("N\n");
			}
		}
		M--;
	}

	return 0;
}

前缀和数组,差分数组

这里将两个数组放在一起总结。

前缀和数组

可以在求连续一部分数列的和时节省时间。

prefix[ i ] = prefix[ i-1 ] + num ( 当前项的前缀和 = 前一项的前缀和 + 当前项 )

将每个前缀和求出,得到一个前缀和数组,在之后要取一段连续部分的和的时候就很方便。

直接使用prefix[ R ] - prefix[ L-1 ]即可。

下面给出模版代码:

    for (int i = 1; i <= n; i++) {
        prefix[i] = prefix[i - 1] + flo[i];
      
    }

差分数组

差分数组的出现,可以便于将一个连续区间的所有数进行增减操作。

这边不总结具体原理,可以去推荐博客复习

(前缀和数组和差分数组都在同一篇:【算法与数据结构】—— 前缀和与差分_前缀和差分为什么书上没有-优快云博客

首先需要构建一个原始的差分数组( 差分 = 当前项 - 前一项 ),然后对于一个区间,例如x~y这个区间的所有数进行增减操作,那么就将差分数组中x的位置和y后面的一个位置做相应的增减操作。

当增减操作完毕后,需要将得到新的数组,(新项 = 新项的前一项 + 对应位置的差分)

代码模版:

//这个是差分数组的创建
for(int i=1; i<=n; i++)
{
	scanf("%d",&ary[i]);
	subfix[i]=ary[i]-ary[i-1];
}
// 执行m次操作 
	for(int i=m;i>0;i--){
		scanf("%d%d%d",&l,&r,&v);
		subfix[l] += v;
		subfix[r+1] -= v;
	}
	// 新数组
	for(int i=1;i<=n;i++){
     
      ary[i] = ary[i-1] + subfix[i];

} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值