小白学算法之差分篇

95 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

差分与前缀和的概念就是相互转换的 --无苦邪

一维差分

1.概念

s[3]=a[1]+a[2]+a[3]; s是a的前缀和,而a[i]就称为s的差分数组

前面学过前缀和数组的创建,此时a是作为已知量

s[i]=s[i-1]+a[i]

差分数组就是进行调换,但注意此时s是作为已知量的

a[i]=s[i]-s[i-1]

2.用处

那么差分可以用来干什么呢?我们拿例题进行说明

797. 差分 - AcWing题库

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

接下来输入 mm 个操作,每个操作包含三个整数 l,r,cl,r,c,表示将序列中 l,r 之间的每个数加上 cc。

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

看了题目,便知道差分是用来对某一区间的数进行操作。

有比较帅的读者会说:我为什么不用for循环呢

for(int i=左区间;i<右区间;i++),帅读者可以自己一试,会超时,毕竟给的区间小的那for循环无事,但比较大的话那时间耗费就久了,所以引出了差分的用法。

3.模板介绍

void insert(int l,int r,int add)
{
    B[l]+=add;
    B[r+1]-=add;
}

先知道B是差分数组,A是B的前缀和即所求的数字

那么B[l]+=add,就会使得A[I]到A[末尾]的所有数都会+=add

解释:

B[2]+=add;
A[2]=B[1]+B[2]
A[3]=B[1]+B[2]+B[3]

同样B[r+1]-=add,导致A[r+1]到A[末尾]的数都会-=add,

就导致只有A[l]到A[r]的数最后+=add

4.例题详解

#include<iostream>
using namespace std;
const int MAX=1e5+10;
int A[MAX],B[MAX];
void insert(int l,int r,int add)
{
    ...
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&A[i]);
        //构建差分数组
        // B[i]=A[i]-A[i-1];
        //相当于 B[i]+=add B[i+1]-=add 等于B[i]=add
        insert(i,i,A[i]);
    }
    while(m--)
    {
        int l,r,c;
        cin>>l>>r>>c;
        insert(l,r,c);
    }
    for(int i=1;i<=n;i++)
    {
        B[i]+=B[i-1];
        cout<<B[i]<<" ";
    }
    
}

二维差分

前面介绍了一维前缀和 和 二维前缀和,那么二维差分矩阵便是一个道理

依旧通过例题讲解

798. 差分矩阵 - AcWing题库

输入一个 nn 行 mm 列的整数矩阵,再输入 qq 个操作,每个操作包含五个整数 x1,y1,x2,y2,cx1,y1,x2,y2,c,其中 (x1,y1)(x1,y1) 和 (x2,y2)(x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。

每个操作都要将选中的子矩阵中的每个元素的值加上 cc。

请你将进行完所有操作后的矩阵输出。

1.模板介绍

void insert(int x1,int x2,int y1,int y2,int c)
{
    x1,y1位置加上了c后,那么后面的全部都会加上c
    B[x1][y1]+=c;
    B[x2+1][y2+1]+=c;
    B[x1][y2+1]-=c;
    B[x2+1][y1]-=c;
}

B[x1][y1]+=c; 这一步会使该点到右下角点的A数全部+=c

B[x2+1][y1]-=c; 蓝色部分的全部数-=c

B[x1][y2+1]-=c下面蓝色部分全部是-=c

因为两个蓝色部分重复减去了右下角部分,所以B[x2][y2]+=c

2.例题详解

#include<iostream>
using namespace std;
const int MAX=1010;
int A[MAX][MAX],B[MAX][MAX];
void insert(int x1,int x2,int y1,int y2,int c)
{
 ....
}
int main()
{
    int n,m,p;
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>A[i][j];
            //构建差分数组
            insert(i,i,j,j,A[i][j]);
        }
    }
    while(p--)
    {
        int x1,x2,y1,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,x2,y1,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]<<" ";
        }
        cout<<endl;
    }
    
    return 0;
}