前言
2023.1.9 重学了前缀和与差分算法,特此写一篇小博客。
前缀和
应用场景
多次求区间和
算法描述
Σ
Σ
Σf[i]
=
a
[
i
]
+
f
[
i
−
1
]
= a[i]+f[i-1]
=a[i]+f[i−1]
非常的好理解,字面意思
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,q;
int a[maxn],f[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
f[i]=f[i-1]+a[i];//求每一位的前缀和
}
//q次查询
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",f[r]-f[l-1]);//区间和输出
}
return 0;
}
差分
应用场景
多次进行区间修改
算法描述
差分算法主要是前缀和算法来支持的一个算法
假设我们要把 a [ l ] a [ r ] ( 包括 a [ l ] 和 a [ r ] ) 同一加上一个 x a[l]~a[r](包括a[l]和a[r])同一加上一个x a[l] a[r](包括a[l]和a[r])同一加上一个x 如何便捷实现?
我们先想一个最朴素的办法,直接 f o r ( i n t i = l ; i < = r ; i + + ) a [ i ] + = x ; for(int i=l;i<=r;i++)a[i]+=x; for(inti=l;i<=r;i++)a[i]+=x;循环一遍,时间复杂度为 O ( n ) O(n) O(n),如果进行过多次的修改,时间复杂度直接爆了,所以需要优化。
差分算法诞生了
- 定义一个新的数组 b [ ] b[] b[]
- 将 a [ i ] − a [ i − 1 ] ( 1 ≤ i ≤ n ) a[i]-a[i-1](1≤i≤n) a[i]−a[i−1](1≤i≤n)的值记录在 b [ i ] b[i] b[i]中
- 进行修改操作,使 b [ l ] + = x , b [ r + 1 ] − = x b[l]+=x,b[r+1]-=x b[l]+=x,b[r+1]−=x
- 待所有修改操作完成后,求一遍前缀和(巧妙抵消),回得到新的 a [ 1 ] … … a [ n ] a[1]……a[n] a[1]……a[n]
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,q;
int a[maxn],b[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i]-a[i-1];//求差
}
//q次修改操作
scanf("%d",&q);
while(q--){
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
//修改
b[l]+=x;
b[r+1]-=x;
}
//求b[]前缀和《=》a[]修改后的形式
for(int i=1;i<=n;i++)a[i]=a[i-1]+b[i];
//输出新数组a[]
for(int i=1;i<=n;i++)printf("%d ",a[i]);
printf("\n");
return 0;
}
补充
有时前缀和会与差分结合