差分
记录累计差值,相当于输入前缀和数组,计算保留"原数组",差分和前缀和是互逆操作;
思想
给定我们一个数组a[0],a[1],a[2]....a[n]
我们做一个数组b[0],b[1],b[2]...b[n]
b[i]符合b[i]=a[i]-a[i-1]
此时b是a的差分,a是b的前缀和
要求在a[l]到a[r]中的所有数都加上c
因为a是b的前缀和,只需要在b[l]+c
a[l]以及a[l]到a[n]所有数,都会+c
只需要在b[r+1]-c,b[r+1]以及b[r+1]到b[n]所有数都会减c
这里的n指的是数组末尾
一维差分经典题目
代码
cpp
#include<iostream>
using namespace std;
int sun[100010],arr[100010],xsun[100010];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>sun[i];//求差分,输入的数组是前缀和数组
arr[i]=sun[i]-sun[i-1];//求差分数组
}
while(m--){
int l,r,c;
cin>>l>>r>>c;
//因为sum是arr的前缀和,只需要在arr[l]+c
//sun[l]以及sun[l]到sun[n]所有数,都会+c
//n是数组最后一个下标
arr[l]+=c;
//同样,因为因为sum是arr的前缀和,a[r+1]-c
//sun[r+1]以及sun[r+1]到sun[n]所有数,都会-c
arr[r+1]-=c;
}
for(int i=1;i<=n;i++){
xsun[i]=arr[i]+xsun[i-1];//输出改变完值的arr的前缀和数组
cout<<xsun[i]<<' ';
}
return 0;
}
二维差分
题目
思路
把给定的数组当做前缀和数组sun读入,读入的同时求sun的差分,或者说原数组
利用求出的差分数组arr,如果要对一个子矩阵添加删除
只需要对arr数组进行操作,就可以在O(1)的复杂度下批量增删sun数组
假设题目要求对x1,y1,x2,y2子矩阵+c
第一步

假设第二步

实际第二步




上图转换成代码
cpp
//arr[x1][y1]+c
//则其前缀和数组从[x1][y1]开始每个都+c
arr[x1][y1]+=c;
//arr[x2+1][y1]-c,因为只加子矩阵x1,y1,x2,y2
//所以去掉多加的部分
arr[x2+1][y1]-=c;
//这里也是去掉多+的部分
arr[x1][y2+1]-=c;
//两次去掉多+的部分过程中
//有重复删除的部分,把重复删除的部分,添加上一次
arr[x2+1][y2+1]+=c;
减完之后,我们就可以求arr的二维前缀和xsun
然后输出xsun即可
代码
cpp
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int sun[1010][1010],arr[1010][1010],xsun[1010][1010];
int main(){
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&sun[i][j]);//把初始数组当成前缀和数组输入
//利用前缀和数组计算原数组
//或者说计算差分数组
//差分数组通过sun[i][j]减去arr[i][j]+arr[i][j-1]获取
//arr[i][j]+arr[i][j-1]的值通过sun不断减去获得
//具体过程和求前缀和加法逻辑一样
arr[i][j]=sun[i][j]-sun[i-1][j]-sun[i][j-1]+sun[i-1][j-1];
}
}
//q次询问
while(q--){
int x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
//arr[x1][y1]+c
//则其前缀和数组从[x1][y1]开始每个都+c
arr[x1][y1]+=c;
//arr[x2+1][y1]-c,因为只加子矩阵x1,y1,x2,y2
//所以去掉多加的部分
arr[x2+1][y1]-=c;
//这里也是去掉多+的部分
arr[x1][y2+1]-=c;
//两次去掉多+的部分过程中
//有重复删除的部分,把重复删除的部分,添加上一次
arr[x2+1][y2+1]+=c;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
//求arr的二维前缀和
xsun[i][j]=arr[i][j]+xsun[i-1][j]+xsun[i][j-1]-xsun[i-1][j-1];
cout<<xsun[i][j]<<" ";
}
cout<<endl;
}
return 0;
}