一维
对于一个数列 ,我们需要维护的数据是“相邻两个数之差”。这种策略是,令
,即相邻两数的差。我们称数列
为数列
的差分数列。
它可以维护多次对序列的一个区间加上一个数,并在最后询问某一位的数或是多次询问某一位的数。譬如使 [l, r] 每个数加上一个 k,就是 ,最后做一遍前缀和。
p [i] = p [i] +p [ i−1]
就是对这个差分数列 做一遍前缀和就得到了原来的数列
,即
相当于
这个前缀和。
极大的缩减了时间复杂度,时间复杂度就是 O(n)。
AC代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+6;
int s[MAXN] = {};
int p[MAXN] = {};
int main() {
int n,m;
scanf("%d%d", &n, &m);
int i;
for (i=1; i<=n; i++) {
scanf("%d", &s[i]);
p[i] = s[i] - s[i-1];
}
for (i=0; i<m; i++) {
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
p[l] += c;
p[r+1] -= c;
}
//输出
int ans=p[0];
for (i=1; i<=n; i++) {
ans += p[i];
printf("%d ", ans);
}
printf("\n");
return 0;
}
二维
题目描述
输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,其中 (x1, y1) 和 (x2, y2) 表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上 c。
请你将进行完所有操作后的矩阵输出。
输入
第一行包含整数 n,m,q。
接下来 n 行,每行包含 m 个整数,表示整数矩阵。
接下来 q 行,每行包含 5 个整数 x1,y1,x2,y2,c,表示一个操作。
输出
共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。
根据二维前缀和表示的是右上角矩形的和,由于差分只涉及前面相邻的数(由一维可以推出),并且由前面范围的数相加得到这个位置的数。那么类比二维前缀和和一维差分,可以简单推测出二维差分的公式
如何从差分矩阵得到原矩阵呢?可以参考下面公式
类比一维可得出每次输入5 个整数 x1,y1,x2,y2,c,表示一个操作。
-
p[x1][y1] += c;
-
p[x1][y2+1] -=c;
-
p[x2+1][y1] -=c;
-
p[x2+1][y2+1] += c;
AC代码
#include <bits/stdc++.h>
using namespace std;
int a[1005][1005] ={0};
int p[1005][1005] ={0};
int main() {
int n,m,q;
scanf("%d%d%d", &n, &m, &q);
int i, j;
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
scanf("%d", &a[i][j]);
p[i][j] = a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
}
}
for (i=0; i<q; i++) {
int x1, y1, x2, y2, c;
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
p[x1][y1] += c;
p[x1][y2+1] -=c;
p[x2+1][y1] -=c;
p[x2+1][y2+1] += c;
}
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
p[i][j] += p[i-1][j]+p[i][j-1]-p[i-1][j-1];
printf("%d ", p[i][j]);
}
printf("\n");
}
return 0;
}