前缀和+差分梳理&模板
Motbloveut221 · · 算法·理论
简而言之,如果说连续函数有微积分,那么离散数列就有差分和前缀和
两者相互依存,也是彼此的逆运算
前缀和的实现方式很简单,只要每次新录入一个数就加上那个数就可以了
int a[N];
int prefix[N] = {0};
for(int i=1;i<=N;i++){
cin >> a[i];
prefix[i] = prefix[i-1]+a[i];
}
差分类似,只要每次新录入一个数就减去前面的数就好了
int a[N];
int diff[N] = {0};
for(int i=1;i<=N;i++){
cin >> a[i];
diff[i] = a[i]-a[i-1];
}
两者是把众人从
换句话说就是一系列
臭名昭著
的题目的罪魁祸首,线段树,树状数组,可持久化线段树的下位替代
以下为主要用法
1.区间求和
前缀和数组的第i个位置,存储的是索引从0到i的所有元素之和,第j个位置存储的是从0到j的所有元素之和
那假设,你拿前缀和数组的第i个位置去减第j-1个位置,你是不是就可以得到第j到第i个元素的和?
只需要在输入输出的时候完成一步预处理,你就可以把后面所有的区间求和问题统统降到
纯粹的数值纯粹的强大
2.区间加
考虑,差分可以理解为数列在某一点的微分,如果你把这一段整体抬升多少,其实并不会改变区间中段的差分大小
你改变的无非就是头尾的差分而已
考虑如果你要区间加C,那你头部的差分也要加C
而由于前一个元素增加了C,尾部的差分需要减C
你只需要
纯粹的数值纯粹的强大
进一步拓展,还有二维的前缀和,以及二维的差分
二维前缀和顾名思义就是一个数组中的矩形中的所有值的和,二维差分略难感性理解,但的确也是前缀和的逆运算
如果你想要知道一个点的前缀和,应该如何递推?可以参考
对于a[x][y]的前缀和pre[x][y],其等于a[x][y]+pre[x][y-1]+pre[x-1][y]-pre[x-1][y-1]
你在求中间两个矩形的前缀和的时候,会不可避免地导致其中有一部分被计算两次,因此最后的减法是拿来去重用的
随后,只要取它的,呃,逆映射/反函数之类的东西你就可以得到a[x][y]的差分:
diff[x][y] = a[x][y]-a[x-1][y]-a[x][y-1]+a[x][y]
当然,差分和前缀和由于两者性质相悖,不能合二为一,如果你想合二为一,你可以去学树状数组和线段树