差分学习笔记与总结
差分
一维差分
What
差分可理解为前缀和的逆运算 前缀和
背景
现有数组
使得
的值
的值
的值
的值
简而言之,
怎么用
作用1
现有数组
,需构造数组 .
使得.
数组为原数组, 数组即为 的差分数组。
所以,对
由
作用2
使区间
即
只需要对
只需
以下是解释(证明)
通过简单观察(思考),得到以下结论:
后再通过前缀和得到 时, 中 区间 元素都会 加上 . 后再通过前缀和得到 时, 中 区间 元素都会 减去 .
所以,只需
复杂度由
所以
当
可用这种方式思考如何构造。
模板
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
例题 link
AcWing 797. 差分 题目入口
题目大意
输入一个长度为
接下来输入
请你输出进行完所有操作后的序列。
CODE
点击查看代码1
/*
a, b 数组可理解为均为0.
当a被赋值时,可理解为[i,i]中的元素加上b[i]
*/
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
void insert(int l, int r, int c) // 模块化
{
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ )
insert(i, i, a[i]);
while (m -- )
{
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for (int i = 1; i <= n; i ++ ) // 前缀和处理
b[i] += b[i - 1];
for (int i = 1; i <= n; i ++ )
printf("%d ", b[i]);
return 0;
}
点击查看代码1
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int m, n;
int a[N], b[N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
{
cin >> a[i];
b[i] = a[i] - a[i - 1];
}
while (m -- )
{
int l, r, c;
cin >> l >> r >> c;
b[l] += c, b[r + 1] -= c;
}
for (int i = 1; i <= n; i ++ )
{
a[i] = a[i - 1] + b[i];
cout << a[i] << ' ';
}
return 0;
}
二维差分
同样,二维差分与一维差分是一样的道理。
What
有原矩阵
同样的,只需要原矩阵
即
所以,
作用
给其中的一个子矩阵加上
令这个子矩阵的左上端点为
只需要
解释/证明
结论:
后再通过前缀和得到 时, 中 区左上端点为 ,右下端点为 (矩阵右下角)的矩阵 中所有元素都会加上 . 后再通过前缀和得到 时, 中 区左上端点为 ,右下端点为 (矩阵右下角)的矩阵 中所有元素都会减去 .
所以,如图
便能得到
只需要
构造二维差分也可以理解为在一个仅由一个元素组成的矩阵(左上端点为
模板
给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c
模板题
AcWing 798. 差分矩阵 题目入口
题目大意
输入一个
每个操作都要将选中的子矩阵中的每个元素的值加上
请你将进行完所有操作后的矩阵输出。
CODE
点击查看代码1
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &a[i][j]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
insert(i, j, i, j, a[i][j]);
while (q -- )
{
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1]; // 前缀和
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= m; j ++ )
printf("%d ", b[i][j]);
puts("");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!