一维差分
数组int a[5]={1,3,7,5,2}
前缀和数组a[i]+=a[i-1];
差分数组 d[i]=a[i]-a[i-1]; 差分数组前缀和d[i]+=d[i-1];
差分数组和原数组的关系:
对 差分数组 进行 求 前缀和 得到 原数组
1 3 7 5 2 a[i]
1 2 4 -2 -3 d[i]
1 3 7 5 2 d[i] (sum)
对区间
[0,2]+1
[1,3]-3
[2,4]+5
一般的方法我们是进行for循环,找到特定的位置然后进行运算,
但是这样会浪费太多的时间
这里,我们进行差分标记,我们对差分数组进行运算
a[L1,R1]+1 <=>d[L1]+1,d[R1+1]-1
a[L2,R2]-3 <=>d[L2]-3,d[R2+1]+3
a[L3,R3]+5 <=>d[L3]+5,d[R3+1]-5
——————————————————————
举个栗子:
0 0 0 0 0 0 ------ 0 1 0 0 -1 0 (对区间[1,3]+1)
0 0 0 0 0 0 ------ 0 1 1 1 0 0
#include<iostream>
using namespace std;
int d[6];
/* 0 1 2 3 4
1 3 7 5 2
2 4 8 5 2
2 1 5 2 2
2 1 10 7 7
*/
void add(int l,int r,int v)
{
d[l]+=v;
d[r+1]-=v;
}
void func()
{
int i;
int a[]={1,3,7,5,2};
add(0,2,1); //0,2
add(1,3,-3); //1,3
add(2,4,5); //2,4
for(i=1;i<5;i++) d[i]+=d[i-1];
for(i=0;i<5;i++){
a[i]+=d[i];
cout<<a[i]<<" ";
}
}
int main()
{
func();
return 0;
}
二维差分
1 5 6 8
9 6 7 3
5 3 2 4
(0,0)到(2,1) +3 (1,1)到(2,2) -1
先进行差分标记
3 0 -3 0 0————3 3 0 0 0
0 -1 0 1 0————3 2 -1 0 0
0 0 0 0 0————3 2 -1 0 0
-3 1 3 -1 0————0 0 0 0 0
——————————————
1 5 6 8————4 8 6 8
9 6 7 3————12 8 6 3
5 3 2 4————8 5 1 4
#include<iostream>
using namespace std;
const int n=3,m=4;
int a[n][m]={ {1,5,6,8},
{9,6,7,3},
{5,3,2,4} };
//(0,0)到(2,1) +3 (1,1)到(2,2) -1
int d[n+1][m+1];
int sum[n+1][m+1];
void add(int x1,int y1,int x2,int y2,int v)
{
d[x1][y1]+=v;
d[x2+1][y1]-=v;
d[x1][y2+1]-=v;
d[x2+1][y2+1]+=v;
}
void func()
{
int i,j;
add(0,0,2,1,3);
add(1,1,2,2,-1);
for(i=0;i<n+1;i++){
for(j=0;j<m+1;j++){
cout<<d[i][j]<<" ";
}cout<<endl;
}cout<<endl;
//引入sum的原因是d[-1][-1]无法访问
sum[0][0]=d[0][0]; //第一个
for(i=1;i<m;i++)
sum[0][i]=sum[0][i-1]+d[0][i]; //第一行
for(j=1;j<n;j++)
sum[j][0]=sum[j-1][0]+d[j][0]; //第一列
for(i=1;i<n;i++){
for(j=1;j<m;j++){
sum[i][j]=d[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
}//上面这一循环其实是二维前缀和的变形
//d[i][j]+=d[i][j-1]+d[i-1][j]-d[i-1][j-1];
}
for(i=0;i<n;i++){
for(j=0;j<m;j++){
cout<<sum[i][j]<<" ";
}cout<<endl;
}cout<<endl;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
a[i][j]+=sum[i][j];
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
int main()
{
func();
return 0;
}