一维差分
问题描述
给定一个长度为 nn 的序列 aa。
再给定 mm 组操作,每次操作给定 33 个正整数 l,r,dl,r,d,表示对 al∼ral∼r 中的所有数增加 dd。
最终输出操作结束后的序列 aa。
Update:由于评测机过快,n,mn,m 于 2024-12-09 从 105105 加强至 2×1052×105,杜绝暴力通过本题。
输入格式
第一行输入两个正整数 n,mn,m。(1≤n,m≤2×1051≤n,m≤2×105)
第二行输入 nn 个正整数 aiai。(1≤i≤n,1≤ai≤1041≤i≤n,1≤ai≤104)。
接下来 mm 行,每行输入 33 个正整数 l,r,dl,r,d。(1≤l≤r≤n,−104≤d≤1041≤l≤r≤n,−104≤d≤104)。
输出格式
输出 nn 个整数,表示操作结束后的序列 aa。
样例输入
6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
样例输出
3 4 5 3 4 2
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,q;
cin >> n >> q;
vector<int> a(n+1,0);
for(int i=1;i<=n;i++){
cin >> a[i];
}
vector<int> diff(n+1,0);
while(q--){
int x1,y1,d;
cin >> x1 >> y1 >> d;
diff[x1] += d;
if(y1+1 <= n){
diff[y1+1] -= d;
}
}
for(int i=1;i<=n;i++){
diff[i] += diff[i-1];
a[i] += diff[i];
}
for(int i=1;i<=n;i++){
cout << a[i] << " ";
}
}
二维差分
问题描述
给定一个 n×mn×m 大小的矩阵 AA。
给定 qq 组操作,每次操作为给定 55 个正整数 x1,y1,x2,y2,dx1,y1,x2,y2,d,Ax1,y1Ax1,y1 是子矩阵左上角端点,Ax2,y2Ax2,y2 是子矩阵右下角端点,你需要给其中每个元素都增加 dd。
输出操作结束后的矩阵 AA。
输入格式
第一行输入 33 个正整数 n,m,qn,m,q。(1≤n,m≤103,1≤q≤1051≤n,m≤103,1≤q≤105)
接下来 nn 行每行输入 mm 个整数,表示 Ai,jAi,j。(−103≤Ai,j≤103,1≤i≤n,1≤j≤m)(−103≤Ai,j≤103,1≤i≤n,1≤j≤m)
接下来 qq 行,每行输入 55 个正整数 x1,y1,x2,y2,dx1,y1,x2,y2,d。(1≤x1≤x2≤n,1≤y1≤y2≤m,−103≤d≤103)(1≤x1≤x2≤n,1≤y1≤y2≤m,−103≤d≤103)
输出格式
输出 nn 行 mm 个整数,表示操作结束后的矩阵 AA。
样例输入
3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1
样例输出
2 3 4 1
4 3 4 1
2 2 2 2
二维差分的举例:
假设我们有一个 4x4 的矩阵,并且我们需要对子矩阵 (1,1)
到 (3,3)
所有元素加 5
想变成
就可以用差分来做
差分数组diff样子
按四点更新规则diff数组会变成这个样子
然后每行从左到右累加:
再然后每列从上到下累加:
下面代码:
#include <iostream>
#include <vector>
using namespace std;
void solve() {
int n, m, q;
cin >> n >> m >> q;
vector<vector<int>> A(n + 1, vector<int>(m + 1, 0));
vector<vector<int>> diff(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> A[i][j];
}
}
for (int i = 0; i < q; ++i) {
int x1, y1, x2, y2, d;
cin >> x1 >> y1 >> x2 >> y2 >> d;
diff[x1][y1] += d;
if (x2 + 1 <= n) diff[x2 + 1][y1] -= d;
if (y2 + 1 <= m) diff[x1][y2 + 1] -= d;
if (x2 + 1 <= n && y2 + 1 <= m) diff[x2 + 1][y2 + 1] += d;
}
//一步到位的前缀和累加
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
diff[i][j] += diff[i - 1][j]; //累加上方
diff[i][j] += diff[i][j - 1]; //累加左方
diff[i][j] -= diff[i - 1][j - 1]; //减去重复累加的左上角
A[i][j] += diff[i][j]; //更新矩阵元素
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cout << A[i][j] << " ";
}
cout << endl;
}
}
int main() {
solve();
return 0;
}