课堂内容
二维前缀和
s
i
,
j
=
Σ
1
i
Σ
1
j
a
x
,
y
s_{i,j}=\Sigma_1^i\Sigma_1^ja_{x,y}
si,j=Σ1iΣ1jax,y
构建:
s
i
,
j
=
a
i
,
j
+
s
i
−
1
,
j
+
s
i
,
j
−
1
−
s
i
−
1
,
j
−
1
s_{i,j}=a_{i,j}+s_{i-1,j}+s_{i,j-1}-s_{i-1,j-1}
si,j=ai,j+si−1,j+si,j−1−si−1,j−1 (容斥原理)
查询:
s
x
2
,
y
2
−
s
x
2
,
y
1
−
1
−
s
x
1
−
1
,
y
2
+
s
x
1
−
1
,
y
1
−
1
s_{x_2,y_2} - s_{x_2,y_1 - 1} - s_{x_1 - 1,y_2} + s_{x_1 - 1,y_1 - 1}
sx2,y2−sx2,y1−1−sx1−1,y2+sx1−1,y1−1
画图推导
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10;
int a[N][N], s[N][N];
int n, m;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << s[i][j] << " ";
}
cout << endl;
}
int q;
cin >> q;
while (q--) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
cout << s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1] << endl;
}
return 0;
}
前缀和的逆过程
二维差分
t
i
,
j
=
a
i
,
j
−
a
i
−
1
,
j
−
a
i
,
j
−
1
+
a
i
−
1
,
j
−
1
t_{i,j} = a_{i,j} - a_{i - 1,j} - a_{i,j - 1} + a_{i - 1,j - 1}
ti,j=ai,j−ai−1,j−ai,j−1+ai−1,j−1
修改:
t
x
1
,
y
1
+
=
n
u
m
t_{x_1,y_1} += num
tx1,y1+=num (增加影响)
t
x
1
,
y
2
+
1
−
=
n
u
m
t_{x_1,y_2 + 1} -= num
tx1,y2+1−=num (消除影响)
t
x
2
+
1
,
y
1
−
=
n
u
m
t_{x_2 + 1,y_1} -= num
tx2+1,y1−=num (消除影响)
t
x
2
+
1
,
y
2
+
1
+
=
n
u
m
t_{x_2 + 1,y_2 + 1} += num
tx2+1,y2+1+=num (消除多了一块,要减掉)
得到修改后的数组:
a
i
,
j
=
Σ
1
i
Σ
1
j
t
x
,
y
=
t
i
,
j
+
t
i
−
1
,
j
+
t
i
,
j
−
1
−
t
i
−
1
,
j
−
1
a_{i,j}=\Sigma_1^i\Sigma_1^jt_{x,y}=t_{i,j}+t_{i-1,j}+t_{i,j-1}-t_{i-1,j-1}
ai,j=Σ1iΣ1jtx,y=ti,j+ti−1,j+ti,j−1−ti−1,j−1
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10;
int a[N][N], s[N][N], t[N][N];
int n, m;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
t[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1];
cout << t[i][j] << " ";
}
cout << endl;
}
int q;
cin >> q;
while (q--) {
int x1, y1, x2, y2, num;
cin >> x1 >> y1 >> x2 >> y2 >> num;
t[x1][y1] += num;
t[x1][y2 + 1] -= num;
t[x2 + 1][y1] -= num;
t[x2 + 1][y2 + 1] += num;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
a[i][j] = t[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}
题目讲解
P3397 地毯
核心代码:
a[x1][y1]+=1;
a[x2+1][y1]-=1;
a[x1][y2+1]-=1;
a[x2+1][y2+1]+=1;
作业
https://www.luogu.com.cn/contest/154442#problems
外加P8218 P3406