开启掘金成长之旅!这是我参与「掘金日新计划 · 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.用处
那么差分可以用来干什么呢?我们拿例题进行说明
输入一个长度为 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]<<" ";
}
}
二维差分
前面介绍了一维前缀和 和 二维前缀和,那么二维差分矩阵便是一个道理
依旧通过例题讲解
输入一个 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;
}