当前位置: 首页 > news >正文

前缀和与差分

前言

其实这本来是一个很小的知识点,但是其中蕴含了一些后面常用的思想,所以我不得不讲一下。

前缀和

前缀和,说白了就是存储每一个前缀的和。至于这个前缀是什么,我们需要简单分类。

一维前缀和

一维前缀和,就是求对于一个数组 \(a_1,a_2,\dots,a_n\) 的前缀和,显然 \(s_i=a_1+a_2+\dots+a_i\)

这个东西的用处也很简单:比如你要求区间 \([l,r]\)\(a_i\) 的和,也就是 \(a_l+a_{l+1}+\dots+a_r\),那么我们可以把等式改写为 \(a_1+a_2+\dots+a_r-(a_1+a_2+\dots+a_{l-1})=s_r-s_{l-1}\),这样我们就从一次 \(O(n)\) 的扫描变成了 \(O(1)\) 的询问。

这个东西大部分时候的用处都在于优化时间复杂度(因为它可以把一个求和过程从 \(O(n)\) 变成 \(O(1)\))。

至于 \(s_i\) 怎么求,也很简单:我们知道 \(s_i=a_1+a_2+\dots+a_i=a_1+a_2+\dots+a_{i-1}+a_i=s_{i-1}+a_i\),因此如果我们知道了 \(s_{i-1}\),那么我们就可以推出 \(s_i\)。这显然是容易的。

代码还是写一份吧:

s[0]=0;
for(int i=1;i<=n;i++)
{s[i]=s[i-1]+a[i];
}

查询:

int ans=s[r]-s[l-1];

二维前缀和

二维前缀和,说白了还是一种前缀和,只不过它从求一维数组的前缀和,改成了求二维数组的前缀和。

我们设 \(s_{i,j}=a_{1,1}+a_{1,2}+\dots+a_{2,1}+a_{2,2}\dots+a_{i,j}\),那么我们考虑左上角为 \((x_1,y_1)\)、右下角为 \((x_2,y_2)\) 之间的这一块区域的和怎么求。

显然我们可以加上 \(s_{x_2,y_2}\),但是因为上面那一部分不能算,所以我们要减去 \(s_{x_1-1,y_2}\),左边也不能算,所以要减去 \(s_{x_2,y_1-1}\),但是因为左上角被减了两次,所以我们需要额外加回来一次,也就是还要加上 \(s_{x_1-1,y_1-1}\)

所以我们可以得到最终公式就是 \(s_{x_2,y_2}-s_{x_1-1,y_2}-s_{x_2,y_1-1}+s_{x_1-1,y_1-1}\)

那我们要求这个二维前缀和也是很简单,照着上面一维前缀和的方式手推一下就行了。

展示一下最终公式:\(s_{i,j}=s_{i-1,j}+s_{i,j-1}-s_{i-1,j-1}+a_{i,j}\)

前缀和暂时讲到这,因为前缀和真的是一个很简单的知识点,没有特别多要讲的地方。

差分

差分这个东西说着就很有意思了,因为它的思想不止在数字上,也可以扩大到很多方面。

不过为了方便,我们还是从最基础的开始讲。

我们考虑这样一个数列 \(a_1,a_2,\dots,a_n\),如果我要让区间 \([l,r]\) 内的所有数都加上 \(1\),那怎么才能快速操作呢?很遗憾你并不会树状数组、线段树、分块这些高级东西,所以你只能靠别的东西了。

我们考虑构造一个与前缀和相逆的东西,也就是说我们要让 \(a_i\) 成为另一个数列的前缀和,怎么构造呢?我们考虑构造数列 \(a_1,a_2-a_1,a_3-a_2,\dots,a_n-a_{n-1}\),那么你对它做前缀和,你惊人的发现这个数列的前缀和就是原数组,我们把这个数列叫做差分数列。求的方法就是上面写的 \(c_i=a_i-a_{i-1}\)

那么如果我们要让一段区间 \([l,r]\) 里的数全部加 \(1\),我们只需要给 \(c_l\)\(1\),这样后面的数在做前缀和的时候就都会额外加一个 \(1\) 了。但是我们不希望 \(r+1\) 之后的数也加 \(1\),所以我们只需要再给 \(c_{r+1}\)\(1\),这样从 \(r+1\) 开始的所有数都会先加 \(1\) 再减 \(1\),相当于没变。

这样,我们就将一个需要 \(O(n)\) 执行的操作变成了 \(O(1)\)(当然最后还原是 \(O(n)\) 的)。

你可能觉得这东西没什么特别的,但是我告诉你:这个东西的思想是非常有趣的。

它有趣的点在于:我们可以把一个区间操作分解成两个单调操作,从而大大降低操作时的时间复杂度,而在最后才将所有的操作统一处理,实现复杂度的平衡。我们考虑一个更大胆的问题:如果我需要对区间 \([l,r]\) 内的所有数进行一次操作,这个操作可能是各种各样的,那我完全可以想办法在 \(l\) 处存下这个操作,再在 \(r+1\) 处标记删除这个操作,这样我们就可以将多个操作揉在一起,实现一次性操作,从而大大优化时间复杂度。

虽然现在你可能还看不懂,但之后你就明白了。

还是放一下基础代码:

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

修改:

c[l]++,c[r+1]--;

复原:

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

差不多就这些吧,反正这也不是什么大的知识点。

http://www.jsqmd.com/news/1322743/

相关文章:

  • 2026 年更新:大庆靠谱的薄壁无缝钢管制造厂家找哪家,用它做工程,能省多少材料成本还不翻车?-海隆钢管 - 行业严选官
  • kernelpwn初学者必读:从下载源码到调试漏洞的完整步骤
  • 从零部署kkFileView 4.0.0:Spring Boot文件在线预览与Nginx反向代理实战
  • TRIZ创新方法:How-to模型与知识效应库解决技术矛盾实战
  • 2026 佛山顺德区吊车租赁哪家正规?2026本地吊车出租价格明细,24小时就近派车 - 星际AI
  • 2026实力之选:王炀律师及其律所品牌在民商事争议解决与资本市场法律服务领域的专业纵深 - 优企名品
  • AppLovin市值飙升25倍:广告技术平台与第一方内容协同增长解析
  • 860软件工程考研:从知识集群拆解到精准复习策略
  • 电动车怎么邮寄?2026年托运费用及避坑指南 - 快递物流资讯
  • 2026年度按键开关定制服务值得信赖TOP6榜单 - 资讯报道
  • 工业传感与便携医疗中的 PIC24FJ128GA106-I/PT:nanoWatt XLP 低功耗 MCU 应用案例解析
  • 3大核心能力:Budibase如何让AI代理、自动化和应用开发变得简单高效
  • 衢州浙西景观设计施工服务观察与解读 - 资讯报道
  • 新手搭建桌面自动化工具 OpenClaw,无需命令行快速部署(含安装包)
  • 终极Redux性能优化:redux-optimistic-ui如何让你的应用响应速度提升300%
  • 北方家装空气源热泵优先选什么品牌?:【芬尼】寒区稳运 - 17728098551
  • 3分钟搞定Mac NTFS读写:免费开源Nigate工具完全指南
  • 从零部署kkFileView v4.0.0:Spring Boot文件预览服务生产环境实战
  • SpringBoot旅游门票系统开发与高并发优化实践
  • 2026年电机厂家供应实力甄选:步进电机、无刷电机、伺服电机及减速电机系统化定制源头工厂解析 - 优企名品
  • ego lite:7900 Star 的 AI 浏览器,人和 Agent 共用一个浏览器
  • 2024 Q2 AI搜索引擎性能断崖式分化:头部3家平均响应提速41%,而另4家API错误率激增217%——你的系统还安全吗?
  • SSE技术详解:从HTTP实时推送到Spring Boot实战应用
  • H5跳转微信小程序并传参:weixin://dl/business/?t= 方案全解析
  • 20260803 5+2+6 126 28
  • 终极指南:如何用SingleFile一键保存完整网页为单个HTML文件
  • 桌面自动化 AI OpenClaw 部署教程,Windows v2.9.0 一键整合包安装(含安装包)
  • Python变量详解:从基础到高级的内存管理与命名规范
  • 空气能采暖推荐哪个品牌?:【芬尼】供暖长效 - 17728181569
  • ESP32_CAMERA_QR开发环境搭建:10分钟上手ESP-IDF与摄像头驱动配置