前缀和与差分

Day4整理的时候忘了这一块了。。我现在补上它。

并不难理解。

前缀和

其实可以把它理解为数学上的数列的前n项和(对于一个一维数组的前缀和)。

我们定义对于一个数组a的前缀和数组s,s[i] = a[1]+a[2]+...+a[i].

二维前缀和

与一维前缀和类似,设s[i][j]表示所有a[i‘][j‘]的和。(1≤i‘≤i,1≤j‘≤j)

有一点像“矩形的面积”那样,把一整块区域的值都加起来。

前缀和的用途

一般用来求区间和。

对于一维情况,现在我给出一个数列a,要求你回答m次询问,每次询问下标j到k的和。朴素的做法显然是对于每次询问都执行一次相加操作,然后输出结果。这样做是正确的,但是当m过大时就会导致计算次数过多而有可能超时。

超时的原因一目了然,重复计算。那么我们应该怎么改进这个方法呢?想象一下,我们如果先提前算好了每一个位置的前缀和,然后用s[k]-s[j],结果不就是我们这次询问的答案吗?这样便会使计算量大大减小。

对于二维的区间和,也是类似的。

我们借助这个图片研究一下。假设在这个矩阵(二维数组)中,我们要求和的是上图中红色区域。现在我们已经预处理出了所有点的前缀和,现在给定两个点(x1,y1),(x2,y2),我们要求 以这两个点连线为对角线的一个子矩阵的数值之和。暴力做法直接挨个加这个我就不再多说了,反正早晚都得TLE,我们重点考虑用前缀和的快速做法。

首先我们可以把s[x2][y2]求出来,它代表整个大矩形的前缀和,然后我们分别减去它左边多出来的一块的前缀和和下边多出来一块的前缀和,这样就是最终答案了?

不是!这不是最终答案。可以发现,在我们剪掉这两个多出的区域时,下边的一小块被减了两次,但减两次显然是不合理的,我们应该加回来。。

所以对于一次的查询答案ans应该等于s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]

这个二维前缀和也称差分序列。

用差分实现区间操作

给定一个长度为n的数列a,要求支持操作add(L,R,k)表示对a[L]~a[R]的每个数都加上k。并求修改后的序列a。

暴力做法显然,TLE,下一个。

我们考虑用差分的做法。这里 需要一个辅助数组c,c用来记录某一个位置上的总改变量。c[i]表示的是i~n这些元素都加上c[i]这个数。我们对[L,R]区间进行加值操作,在c[L]处加一个k,在c[R+1]处就减去一个k。最后求序列的每个位置变成了多少,只需要求一下c数组的前缀和,然后和原数组按位相加就好。

这个结论的证明我不是太会。。呃记住它是对的就好啦。。

对于二维的情况,一个n*m的矩阵,要求支持操作add(x1,y1,x2,y2,a),表示对于以(x1,y1)为左下角,(x2,y2)为右上角的矩形区域,每个元素都加上a。要求修改后的矩阵。

我们的做法和一维类似。用数组c存储总改变量。在c[x1][y1]处加上a,在c[x2+1][y1]和c[x1][y2+1]处减a,在c[x2+1][y2+1]再加上a。最后(i,k)位置上的数值就是c数组在(i,k)位置的前缀和。

时间: 2024-12-21 18:46:52

前缀和与差分的相关文章

浅谈简单前缀和与差分问题

\(Part1:\) 前缀和与差分的简单定义 考虑一个数组\(A\),其项数为\(n\)项.有\(m\)次询问,每次询问给定两个参数\(l\)和\(r\),要求求出\(A[l]+A[l+1]+...+A[r]\). 怎么做呢? 暴力:显然是\(O(nm)\)的 数据结构维护:显然是\(O(mlogn)\)的 前缀和的用处就在于可以将这样的序列区间求和的问题用\(O(n+m)\)的复杂度,在线性的时间和空间内解决出. 那么前缀和究竟是什么呢? 在读入\(A\)数组的时候,我们预处理出一个前缀和数组

前缀和、二维前缀和与差分

前缀和 假如给出一串长度为n的数列a1,a2,a3...an,再给出m个询问,每次询问给出L,R两个数,要求给出数列在区间[L,R]的和 普通的方法,时间复杂度为O(n*m) int a[100005]; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int sum=0; while(m--){ for(int i=L;i<=R;i++){ sum+=a[i]; } } 前缀和就是前面i个数的总和,对于每个询问,只需要输出a

基础算法 --- 前缀和与差分

前缀和 一个数列A,它的前缀和数列S是能够通过数学方式推断出来的: 部分和 数列A中某个下标区间内和数的和,即: S[i, j]=S[j] - S[i - 1] 前缀和与部分和应用场景 给定m个区间,求每个区间内数的和: 暴力解法:m次循环,循环内部再进行区间循环,这种解法在小量数据场景无问题,如果数值大,会造成超时. 前缀和解法:先计算前缀和,然后循环m次,求每个区间部分和 差分 一个数列A:1.2.3.4.5,它的差分数列为B:1.1.1.1.1,那么有如下特性: 1.数列B的前缀和S[i]

前缀和和差分模板(AcWing 795-798)

前缀和分一维前缀和和二维前缀和,前缀和可以帮我们快速统计一段范围内的合. 需要简单的理解 一维前缀和 —— 模板题 AcWing 795. 前缀和S[i] = a[1] + a[2] + ... a[i]:a[l] + ... + a[r] = S[r] - S[l - 1]: 二维前缀和 —— 模板题 AcWing 796. 子矩阵的和S[i, j] = 第i行j列格子左上部分所有元素的和以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:S[x2, y2] - S[x1 -

TYVJ P1736 创意吃鱼法 Label:dp || 前缀和

题目描述 回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*).她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略. 在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中. 猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的

【差分】BZOJ 1651 [Usaco2006 Feb]Stall Reservations 专用牛棚

显而易见的是我们要求的时间段重叠最多的次数. 用线段树也可以,不过既然是学习和练习前缀和与差分那么就用差分的思想. 在num[a]的位置+1 在num[y+1]位置-1 表示[a,b]区间有一个时间段. 最后统计一下num[i]最多的次数(i是1~n) /************************************************************** Problem: 1651 User: LYFer Language: C++ Result: Accepted Ti

【差分数列】tyvj2042线段问题

线段问题 描述 Description 有N条线段,已知每条线段的起点和终点(50000以内),然后有M个询问,每次询问一个点(50000以内),求这个点在多少条线段上出现过? 输入格式 InputFormat 第一行N线段条数接下来N行,每行两个数,线段的起点和终点第N+2行一个数M询问个数接下来M行,每行一个点 输出格式 OutputFormat 对于每个询问,求答案 样例输入 SampleInput 3 2 5 4 6 0 7 4 2 4 7 6 样例输出 SampleOutput 2 3

初涉差分约束系统

一个把数学问题转化为图论模型的很好的例子 差分约束系统 差分约束系统的定义是:一个由$n$个变量和$m$个约束条件组成,形成$m$个形如$x_i-x_j≤k$的不等式($i,j∈[1,n],k$为常数)的系统. 举个例子(图自网络): 例如这个不等式组就是一个差分约束系统. 我们要求的通常是附加几个条件之后(例如$x_i>0$)的这个系统的最大/小解.因为很容易发现,若只有变量之间的相对限制,这个系统要么是无数解:要么是无解. 那么怎么把这个抽象的不等式组化为图论模型呢? 观察一下这个例子(图仍

Luogu P1083 借教室【二分答案/差分】By cellur925

题目描述 Description 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自然希望编程解决这个问题. 我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借.共有m份 订单,每份订单用三个正整数描述,分别为dj, sj, tj,表示某租借者需要从第sj天到第tj天租 借教室(包括第sj天和第tj天),每天需要租借dj个教室. 我们假定