差分

作用:快速进行区间修改

给定数列$a$,构造数列$b$使得 $a_k=\sum_{\substack{1\le i\le k }} b_i$,则$b$是$a$的差分数组,$a$是$b$的前缀和数组,前缀和与差分互为逆运算

$b[i]=a[i]-a[i-1]$

此时,若需要把$[l,r]$的数加上$x$,则$a_l$到$a_l$都会加上$x$,此时$b[l]=a[l]-a[l-1]$增大了$x$,$b[r+1]=a[r+1]-a[r]$减小了$x$,所以$b[l]+=x,b[r+1]-=x$

修改后,求前缀和即可得到原数组修改后的结果

例:给一个$n$项数列,共$p$次修改,每次把$[l,r]$之间的数加上$x$,求修改后数列的最小值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<bits/stdc++.h>
using namespace std;

const int N=5e6+5;
int n,p;
int a[N],b[N];
int ans=1e9;

int main(){
cin >> n >> p;
for(int i=1;i<=n;i++){
cin >> a[i];
b[i]=a[i]-a[i-1];
}
for(int i=1;i<=p;i++){
int l,r,x;
cin >> l >> r >> x;
b[l]+=x,b[r+1]-=x;
}
for(int i=1;i<=n;i++){
a[i]=a[i-1]+b[i];
ans=min(ans,a[i]);
}
cout << ans;
return 0;
}

二维差分

若$b[x][y]$加上$k$,则从点$(x,y)$到$(n,n)$均加上了$k$,所以要给左上点$(x_1,y_1)$,右下点$(x_2,y_2)$的矩阵加上$k$,则$b[x_1][y_1]+=k,b[x_2+1][y_1]-=k,b[x_1][y_2+1]-=k,b[x_2+1][y_2+1]+=k$

最后求前缀和数组即可

例:有一个$n*n$的矩阵,$m$次修改,每次修改把$(x_1,y_1)$到$(x_2,y_2)$的矩阵加$1$,最后求修改后的矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<bits/stdc++.h>
using namespace std;

const int N=1005;
int n,m;
int b[N][N];

void change(int x_1,int y_1,int x_2,int y_2,int k){
b[x_1][y_1]+=k;
b[x_2+1][y_1]-=k;
b[x_1][y_2+1]-=k;
b[x_2+1][y_2+1]+=k;
}

int main(){
cin >> n >> m;
for(int i=1;i<=m;i++){
int a,b,c,d;
cin >> a >> b >> c >> d;
change(a,b,c,d,1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
cout << b[i][j] << ' ';
}
cout << endl;
}
}