【差分】一维与二维区间段加C

区间段加C(一维差分)

注释

给定a[1],a[2]......a[n]

构造差分数组b[N],使得

a[i]=b[1]+b[2]+....+b[i]

核心操作:将a[L~R]全部加上C,等价于:

b[L]+=C    b[R+1]-=C

结果为

a[1~L-1]无影响

a[L~R]加上了C

a[R+1~N]无影响

在第一个for语句调用insert,

使得b[i]=b[i]-b[i-1]这样使得a[i]=b[1]+b[2]+....+b[i]成立

while里调用insert,使得b[l]+=c;这样由于输出的时候b[l-1]=a[l-1],所以b[l]=c+a[l]

b[r+1]-=c;因为输出的时候b[r]=a[r]+c,所以b[r+1]=b[r+1]+b[r-1]=a[r+1]+c-c=a[r+1]

在第二个for语句,目的是使得b[n]=\sum_{i=1}^{n}bi=a[n](加C后的),将修改后的b[n]输出

时间复杂度由o(n)降到了o(1)

代码段 

#include<bitsstdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int M = 1010;
int n, m, q;
int a[N], tmp[N], s[N],b[N];
int a1[M][M], s1[M][M];
拆分
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]);

二维区间加C(二维差分)

给定a[i][j],构造差分矩阵b[i,j],使得a[][]是b[][]的二维前缀和

a[i][j]=\sum_{x,y=1}^{x=i,y=j}b[x][y]

b[i][j]的通项公式为

b[i][j]=a[i-1][j-1]-a[i-1][j]-a[i][j-1]+a[i][j]

差分核心操作:给以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵中的所有数a[i,j],加上C

对于差分数组的影响:

b[x1,y1]+=C          b[x1,y2+1]-=C

假设(3,3)为(x1,y1),(5,4)为(x2,y2)

注:这里的图示表示的是a[n]即b[n]的前缀和的赋值情况

虽然操作的是b[n],但最后真正影响的是b[n]的前缀和即a[n](因为要输出a[n])

第一个操作将有颜色的部分为被加上C(即后面bn前缀和包含(3,3)的部分)

 第二个操作删去了前缀和含有(3,5)的部分的C

b[x2+1,y1]-=C     b[x2+1,y2+1]+=C

第三个操作则删去前缀和含有(6,3)部分的C 

注意到这里(6,5)又被删去了一次,所以变黑

第四个操作将包含(6,5)的前缀和都加上C后面的元素的前缀和都会加C(恢复原数值)

注释 

首先insert函数相当于封装的一个插入函数,实现的功能是

给定了坐标(x1,y1)和(x2,y2),对bn进行四次操作,操作的行列式形式为

+ -
- +

 得到结果为bn的二维前缀和等于加上去的形参C

实现的原理可以见上方图解

最终在输出前,将b[n][m]进行前n,m项累加操作

b[i][j] += b[i][j - 1] -b[i - 1][j - 1] + b[i - 1][j];

使得每一项b[i][j]=a[i][j](更新后的新a[i][j])

代码段

#define _CRT_SECURE_NO_WARNINGS 
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int M = 1010;
int n, m, q;
int a[N], tmp[N], s[N],B[N];
int a1[M][M], s1[M][M],b[M][M];
void insert(int x1, int y1, int x2, int y2, int c)
{
	b[x1][y1] += c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y1] -= 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", &a1[i][j]);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			insert(i, j, i, j, a1[i][j]);
	while (q--)
	{
		int x1, y1, x2, y2, c;
		scanf("%d%d%d%d%d", &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][j - 1] -b[i - 1][j - 1] + b[i - 1][j];
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
			printf("%d ", b[i][j]);
		puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/nathanqian123/article/details/121280755
今日推荐