知方号

知方号

详解手撕 一维、二维、三维差分数组原理(附图解,模板,例题分析)<什么是一维二维三维空间的概念>

【差分专题】 引言

​ 差分是一种处理数据巧妙而简单的方法,可以应用于区间修改和询问问题。例如,将给定的数据集合 A 分成很多区间,并对这些区间进行很多次操作,每次都是对某段区间内的所有元素做相同的加减操作,此时若一个个的遍历修改这段区间内的每个元素,就会非常的耗时,效率不高。为此,我们引入一个叫 “ 差 分 数 组 ” color{Orange}“差分数组” “差分数组” B,当修改这段区间时,只需要对这段区间的 端 点 color{Purple}端点 端点 进行修改,就能将整段区间的元素修改,这个操作是非常平滑的,只需要 O(1) 的复杂度。当我们将所有修改操作进行完毕后,再利用差分数组,即可计算出新的数据集合 A。

​ 对于集合 A,它可以是一维的线性数组 a[ ],二维矩阵 a[ ] [ ], 三维立体 a[ ] [ ] [ ] 。与之对应的,差分数组 B[ ] ,B[ ] [ ] ,B[ ] [ ] [ ] 。当然如果想象力足够的话四维也是有可能的。

1. 一维差分 1.1 基本概念

问 题 描 述 color{Turquoise}问题描述 问题描述:给定一个长度为 n 的一维数组 a[ ],数组内的每个元素都有初值,并对其进行一下操作:

(1)修改操作:进行 m 次区间修改,每次修改对这段区间【L,R】内的所有元素做相同的加减操作。

(2)查询操作:查询某个元素的值是多少

     ~~~~      如果简单的暴力遍历,那么对于每次的修改复杂度是 O(n) 的,有 m 次修改,此时复杂度为 O(n*m) ,如果用差分法的话,复杂度将为 O(n + m)

原理

     ~~~~      对于这个原数组 a[ ] = {a1,a2,a3,···,an},我们构造出这样一个数组 B[ ] = {b1,b2,b3,···,bn},使得 ai = b1 + b2 + ··· + bi,那么b[ ] 就称为 a[ ] 的差分,a[ ] 称为 b[ ] 的前缀和。可以发现,差分与前缀和是一组逆运算。

     ~~~~     如何利用差分数组对区间进行修改呢?为什么利用差分数组能提升修改的效率呢?

1. 区 间 修 改 color{Purple}区间修改 区间修改,时间复杂度为 O(1)

​ 现在要将原数组 a[ ] 区间【L,R】上的每个数都加上一个 c,如下图所示:

第一个受到影响的差分数组中的元素为 bL],所以 b[L] += c ,对于 a[L] 后面的数都会受到 B[L] 的影响加上 c。最后一个受影响的差分数组中的元素b[R],为了保证不影响到 R 后面的元素,所以我们需要 b[R + 1] -= c。

也就是说,对于 a[x] = b[1] + b[2] + ···+ b[x],利用差分数组能够精确地实现只修改指定区间内元素的目的,而不会修改区间外的a[ ] 的值,也就是:

(1) 1 ≤ x < L, 前缀和 a[x] 不变。(2) L ≤ x ≤ R, 前缀和 a[x] 加上了 c 。(3) R < x ≤ N, 前缀和 a[x] 不变,因为被 b[R + 1] 中的c抵消了。

这样一来,就不必每次都对区间内所有的数进行处理,只需要修改区间【L,R】的两个端点 b[ ] 的值即可,复杂度是 O(1) 的。

void add(int l, int r, int c){ b[l] += c; b[r + 1] -= c;}

2. 单 点 查 询 color{Purple}单点查询 单点查询,时间复杂度为 O(n)

     ~~~~      根据定义,差分数组 b[ x ] 的前缀和 b[1] + b[ 2 ] + ··· + b[ x ] 就是原数组 a[x] 的值

void get(int x){ for(int i = 1; i

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。