差分+差分矩阵(更适合新手宝宝体质)

快速掌握差分以及差分矩阵

文章目录

前言

之前我们提到了前缀和数组与前缀和矩阵,现在我们可以类比处差分矩阵,差分数组

,现在我将站在新手的角度为大家介绍,学完差分的小伙伴们也可以复习一下

差分

差分的定义【官方解释】

差分是指在数学中,对于一个数列或函数,通过计算相邻元素之间的差值来得到一个新的数列或函数。差分可以用来描述数列或函数的变化趋势或规律。

对于一个数列 {a1, a2, a3, ..., an},它的一阶差分可以表示为 {d1, d2, d3, ..., dn-1},其中 di = ai+1 - ai

对于一个函数 f(x),它的一阶差分可以表示为 f'(x) = f(x+1) - f(x)

差分可以应用于各种数学领域,如微积分、离散数学、动态规划等。它在数值计算和数据分析中也有广泛的应用,可以用来处理时间序列数据、图像处理、信号处理等问题。

差分自定义【跟前缀和放在一起理解】

对于一个数组{a1, a2, a3, ..., an},我们可以有前缀和s[N],
s[1]=a[1];
s[2]=a[2]+a[1]
s[3]=a[3]+a[2]+a[1]
............

类比对于一个数组{a1, a2, a3, ..., an}

我们有
b[1]=a[1]-a[0]
b[2]=b[2]-b[1]
b[3]=b[3]-b[2]
................

我们叫{b1, b2, b3, ..., bn}{a1, a2, a3, ..., an}的差分数组;

差分数组的应用

对差分数组的前缀和数组进行范围修改;
a[1]=b[1];
a[2]=b[1]+b[2]
a[3]=b[1]+b[2]+b[3]
........................

数组a[N]就是b[N]的前缀和数组,假设我们要对a[N],进行修改,在【l,r】的范围内加上 w,假如直接对数组 a [ N ] 进行遍历操作,那么我们的时间复杂度是 O(N);

但是我们现在有了差分数组,我们就不用对 a [N ]做直接修改了,我们从它的差分数组入手,对 b[left] 进行修改,那么 a[ i ] ,a [ i+1 ] ,a [ i+2 ], a [ i+3] ...就会发生改变,但是我们不能让改变一直延续下去,所以要在 b [ right ]处进行修改 【及时进行相反的操作,这样就实现了范围修改

题目描述

输入一个长度为 n 的整数序列。

接下来输入 m个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r]

之间的每个数加上 c

请你输出进行完所有操作后的序列。

输入格式第一行包含两个整数 n 和 m

第二行包含 n 个整数,表示整数序列。

接下来 m 行,每行包含三个整数 l,r,c,表示一个操作。

输出格式

共一行,包含 n 个整数,表示最终序列。

数据范围

1≤n,m≤100000

1≤l≤r≤n

−1000≤c≤1000

−1000≤整数序列中元素的值≤1000

输入样例:

6 3

1 2 2 1 2 1

1 3 1

3 5 1

1 6 1

输出样例:

3 4 5 3 4 2

`

cpp 复制代码
#include<iostream>
using namespace std;
const int N =1e5 +7;
int a[N],b[N];
int n,m;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        //由于是前缀和,下标要从 1 开始
        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]=b[i]+a[i-1];//重新构建前缀和
        cout<<a[i]<<' ';
    }
}

差分矩阵【与前缀和矩阵进行比较】

有关前缀和矩阵的知识请看我的另2篇博客

激光矩阵问题: https://blog.csdn.net/2302_77698668/article/details/132345058

前缀和求解k倍区间问题: https://blog.csdn.net/2302_77698668/article/details/132339559

差分矩阵定义【官方解释】

差分矩阵是指由差分操作得到的矩阵。在离散数学和图论中,差分矩阵常用于描述图的性质和图算法的设计。

对于一个无向图 G = (V, E),其中 V 是顶点集合,E 是边集合。差分矩阵 D 是一个 |V| × |V| 的矩阵,其中 |V| 表示顶点的个数。差分矩阵的定义如下:

D(i, j) = -1, if i ≠ j and (i, j) ∈ E,

degree(i), if i = j,

0, otherwise.

其中,D(i, j) 表示差分矩阵的第 i 行第 j 列的元素,degree(i) 表示顶点 i 的度数(即与顶点 i 相连的边的个数)。

差分矩阵可以用来描述图的拉普拉斯矩阵,它是一个对称半正定矩阵,具有很多重要的性质和应用。差分矩阵在图论算法中也有广泛的应用,如最短路径算法、最小生成树算法、图分割算法等。

自定义

跟之前一样,我们继续类比推理
a [i] [j] 矩阵【 b[1] [1](左上端点),b[i][j] 右下端点】的和
那么要对 a [ i ] [ j ]进行范围修改,我们就只需要对 b[N][N]进行修改

修改操作【跟前缀和对比】


为啥差分是从后面开始进行面积加减呢?

想想我们之前提到的

但是我们现在有了差分数组,我们就不用对 a [N ]做直接修改了,我们从它的差分数组入手,对 b[left] 进行修改,那么 a[ i ] ,a [ i+1 ] ,a [ i+2 ], a [ i+3] ...就会发生改变,但是我们不能让改变一直延续下去,所以要在 b [ right ]处进行修改 【及时进行相反的操作,这样就实现了范围修改

差分会对后面的前缀和数组造成影响,对前面的不会影响,一维的数组适用,二维的数组同样适用

题目描述

输入一个 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 个整数,表示所有操作进行完毕后的最终矩阵。

数据范围

1≤n,m≤1000

1≤q≤100000

1≤x1≤x2≤n

1≤y1≤y2≤m

−1000≤c≤1000

−1000≤矩阵内元素的值≤1000

输入样例:

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

直接上代码

代码

cpp 复制代码
#include<iostream>
using namespace std;
const int N =1e3 +7;
int a[N][N],b[N][N];
int n,m,q;
//这里是对 b 数组进行操作,相当于在(x1,y1)->(x2,y2)范围内加上c
void add(int x1,int y1,int x2,int y2,int c){
    b[x2+1][y2+1]+=c;
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    //这里的操作可以参考之前关于差分的描述 
}
int main(){
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            add(i,j,i,j,a[i][j]);
            //通过这个操作只会对 b[i][j]
            //那个点产生影响
        }
    }
    
    while(q--){
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        add(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];
            //这个是前缀和矩阵的计算公式,建议和之前的一维数组类比一下
            cout<<b[i][j]<<' ';
        }
        puts("");
    }
    return 0;
}
相关推荐
xinghuitunan5 分钟前
蓝桥杯顺子日期(填空题)
c语言·蓝桥杯
van叶~7 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法8 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
knighthood200118 分钟前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros
云卓SKYDROID23 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童1 小时前
双指针算法习题解答
算法
小堇不是码农1 小时前
在VScode中配置C_C++环境
c语言·c++·vscode
Jack黄从零学c++1 小时前
C++ 的异常处理详解
c++·经验分享
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存