「学习笔记」前缀和与差分
一维前缀和#
就是一个数列前 项的总和
如何实现前缀和?
代码:
const int N=1e5+10;
int sum[N],a[N]; //sum[i]=a[1]+a[2]+a[3].....a[i];
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
查询某个数或某一段区间的区间和,查询时间复杂度为 ,预处理的时间复杂度为
查询代码:
scanf("%d%d",&l,&r);
printf("%d\n", sum[r]-sum[l-1]);
原理:
求 区间的和
二维前缀和#
其实跟一维的原理一样,只不过它所记录的是是左上角到右下角所包含的矩阵元素的和

如图,蓝色部分是我们要求的,我们可以用目前已知的来求,但这里要注意,在这里被减了2遍,所以要再加上
所以
因而也可以得到二维前缀和的预处理公式:
预处理时间复杂度为 ,查询时间复杂度为
一维差分#
可以看作前缀和的逆运算
给定原数组:
现在构造一个数组:
我们让它们做到
可以看出, 是 数组的前缀和数组,那么反过来, 就是 的差分数组
每一个 ,都是 从 开始到 的区间和
构造:
差分数组有什么用?
让 区间里的元素都加上
按照一般做法,
for(int i=l;i<=r;++i)
{
a[i]+=x;
}
这种做法是 的,数据一大,我们就承受不了这种复杂度了
这里,我们可以考虑差分
上面可以看出,差分记录的只是差,所以 之间不受影响,因为都是加 ,所以差不变,但是, ,那么, ,所以 要加上 (这就是为什么前面我说的是 而不是 ),同理, ,那么,
由此可以看出,我们只要在 b[l]+=x,b[r+1]-=x
,就可以解决问题了,时间复杂度为 (忽略常数)
二维差分#
原理差不多,但相对于二维前缀和,二维差分更复杂一些
我们要始终记得,原数组 是差分数组 的前缀和数组,一旦 有变化,那么, 也会随之改变
构造:
void insert(int x1,int y1,int x2,int y2,int c)
{
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
insert(i,j,i,j,a[i][j]); //构建差分数组
}
}
上面这种构造要把 数组设为空,当然,也有关于二维差分操作也有直接的构造方法,公式如下:
让到的矩阵的元素都加上
因为 ,所以
同理
因为 ,所以
因为 ,所以
因为 ,所以
除去 因为都 ,所以不受影响
求和
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
}
}
这种求和方法, 数组每一次都在变化,而且每一次变化都标留了(+=),当然,也有其他求和版本
long long c[1000][1000];
long long x,y;
scanf("%lld%lld",&x,&y);
for(int i=1;i<=x;++i)
{
for(int j=1;j<=y;++j)
{
c[x][y]+=b[i][j];
}
}
作者:yifan0305
出处:https://www.cnblogs.com/yifan0305/p/16418891.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
转载时还请标明出处哟!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】