目录
(2)二维差分的实现
什么是前缀和呢?
在一个数组中,a[0]~a[i]它的前缀和sum[i]=a[0]+...+a[i]。很显然我们可以以得出a[i]=sum[i]-sum[i-1]。这就是前缀和的大致思想
定义一个差分数组d[i],它的定义是d[i]=a[i]-a[i-1]。易得出差分是前缀和逆运算。那么差分有什么应用呢?
比如说给定一个数组,一开始是有初值的,现在在一定的区间进行m次修改,可能加,可能减,求最后得出的数组值。你如果一个一个操作,毫无疑问数据范围大的肯定超时,这时候就要用到差分知识了。假如在[l,r]区间加1,那么该如何操作呢,应该是d[l]+=1,d[r+1]-=1。
为什么是这样子呢?因为d[i]是差分数组,所以我们知道a[i]=a[i-1]+d[i],也就是说这里的a[i]就相当于是d[i]的前缀和,换句话说a[i]=d[1]+d[2]+d[3]+...+d[i],在[l,r]区间进行修改,d[l]+=1,d[r+1]-=1,那么在区间l前其实并未修改,而在l后却修改了,但是r+1却又将r后面的区间又抵消了。具体我们看下代码的展现吧。
- #include
- using namespace std;
- const int N=1e3+10;
- int a[N],d[N];
- int n,m,l,r,q;
-
- int main()
- {
- cin>>n>>m;
- for(int i=1;i<=n;i++){
- cin>>a[i];
- d[i]=a[i]-a[i-1];
- }
- while(m--){
- cin>>l>>r>>q;
- d[l]+=q;
- d[r+1]-=q;
- }
- for(int i=1;i<=n;i++){
- a[i]=a[i-1]+d[i];
- cout<" ";
- }
- return 0;
- }
- /*
- 5 3
- 1 2 3 4 5
- 1 1 3
- 1 2 1
- 2 2 4
- */

一维差分是好,但也是有局限性的,比如说上面的只是一次查询操作,但如果是多次呢并且查询是单点查询和区间查询呢。这个后面的树状数组以及线段树可以解决,偏题了!!!
比如说这样一道题目吧。
给你一个 n 行 m 列的矩阵 A ,下标从1开始。
接下来有 q 次查询,每次查询输入 4 个参数 x1 , y1 , x2 , y2
请输出以 (x1, y1) 为左上角 , (x2,y2) 为右下角的子矩阵的和,
第一行包含三个整数n,m,q.
接下来n行,每行m个整数,代表矩阵的元素
接下来q行,每行4个整数x1, y1, x2, y2,分别代表这次查询的参数
1 \le n, m \le 10001≤n,m≤1000
1 \le q \le 10^51≤q≤105
-10^9 \le a[i][j] \le 10^9−109≤a[i][j]≤109
1 \le x_1 \le x_2 \le n1≤x1≤x2≤n
1 \le y_1 \le y_2 \le m1≤y1≤y2≤m
输出q行,每行表示查询结果。
题解:如果这样子的题目你觉得还能用一维数组吗?很明显不能,同时你要是一个一个求,这个复杂度我就不多说了吧,过不了。那么就需要用到我们的二维差分了。与一维差分一样,它也有一个差分数组d[i][j],表示的是d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1](大家可以画一个二维坐标感受一下,挺好懂的),那么求的话可以分为直接求前缀和和二维差分前缀和。偏题了,写看下该题怎么写吧。代码如下:
- #include
- using namespace std;
- typedef long long ll;
- ll n,m,q;
- ll a[1010][1010];
-
- int main()
- {
- ios::sync_with_stdio(-1);
- cin>>n>>m>>q;
- for(ll i=1;i<=n;i++){
- for(ll j=1;j<=m;j++){
- cin>>a[i][j];
- }
- }
- for(int i=1;i<=n;i++){
- for(int j=1;j<=m;j++){
- a[i][j+1]+=a[i][j];
- }
- }
- for(int j=1;j<=m;j++){
- for(int i=1;i<=n;i++){
- a[i+1][j]+=a[i][j];
- }
- }
- while(q--){
- //TODO
- int x1,y1,x2,y2;
- cin>>x1>>y1>>x2>>y2;
- }
- return 0;
- }
(2)二维差分的实现
在二维空间中如果对指定的区域进行修改,该如何做呢?与一维数组,一样,创建一个二维差分数组即可,它的公式就是(1)点上面的,其实也都是模板滴啦,我们来看一道模板题,大家就知道了。
描述
给你一个n行m列的矩阵,下标从1开始。
接下来有q次操作,每次操作输入5个参数x1, y1, x2, y2, k
表示把以(x1, y1)为左上角,(x2,y2)为右下角的子矩阵的每个元素都加上k,
请输出操作后的矩阵。
输入描述:
第一行包含三个整数n,m,q.
接下来n行,每行m个整数,代表矩阵的元素
接下来q行,每行5个整数x1, y1, x2, y2, k,分别代表这次操作的参数
1\le n,m \le 10001≤n,m≤1000
1\le q \le 10^51≤q≤105
1\le x1 \le x2 \le n1≤x1≤x2≤n
1\le y1 \le y2 \le m1≤y1≤y2≤m
-10^9 \le 矩阵中的元素 \le 10^9−109≤矩阵中的元素≤109
输出描述:
输出n行,每行m个数,每个数用空格分开,表示这个矩阵。
示例1
输入:
2 3 4
1 2 3
4 5 6
1 1 2 2 3
1 2 2 3 -1
1 1 1 3 4
1 1 2 1 1
复制输出:
9 8 6
8 7 5
- #include
- using namespace std;
- typedef long long ll;
- const int N=1e3+10;
- ll a[N][N],d[N][N];
- ll n,m,q;
-
- int main()
- {
- ios::sync_with_stdio(-1);
- cin>>n>>m>>q;
- for(int i=1;i<=n;i++){
- for(int j=1;j<=m;j++){
- cin>>a[i][j];
- d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];
- }
- }
-
- while(q--){
- ll x1,y1,x2,y2,k;
- cin>>x1>>y1>>x2>>y2>>k;
- d[x2+1][y2+1]+=k;
- d[x1][y1]+=k;
- d[x1][y2+1]-=k;
- d[x2+1][y1]-=k;
- }
- for(int i=1;i<=n;i++){
- for(int j=1;j<=m;j++){
- a[i][j]=a[i-1][j]+a[i][j-1]+d[i][j]-a[i-1][j-1];
- cout<" ";
- }
- cout<
- }
- return 0;
- }
-
相关阅读:
rsync 远程同步
网站内容下载软件有哪些 网站内容下载软件推荐 网站内容下载软件安全吗 idm是啥软件 idm网络下载免费
上周热点回顾(5.8-5.14)
_jb_pytest_runner.py: error: unrecognized arguments: --cov报错
electron初学
[Android]从app的trace打桩原理回顾zygote的fork
狂神说MybatisPlus学习笔记
事务 还有这些用法,之前都不知道
RabbitMQ工作队列
JWT靶场通关(3关)
-
原文地址:https://blog.csdn.net/gaoqiandr/article/details/127664437