什么是差分及其用法

差分:

类似于数学中的求导和积分,差分可以看成前缀和的逆运算。

差分数组:

首先给定一个原数组a:a[1], a[2], a[3],,,,,, a[n];

然后我们构造一个数组b : b[1] ,b[2] , b[3],,,,,, b[i];

使得 a[i] = b[1] + b[2 ]+ b[3] +,,,,,, + b[i]

例如:

a[0 ]= 0;

b[1] = a[1] - a[0];

b[2] = a[2] - a[1];

b[3] =a [3] - a[2];

........

b[n] = a[n] - a[n-1];

也就是说,a数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组。换句话说,每一个a[i]都是b数组中从头开始的一段区间和。

一维差分:

在这里插入图片描述

例题:

/*
	输入:长度为n的整数序列
	再输入 :m个操作,每个操作包含3个整数l,r,c:表示将序列中[l,r]直接的每个数都加上c.
	第一行:n,m
	第二行n个整数
	m行,每行:l,r,c
	输出格式:1行,n个整数,表示最终序列。
	1<=n,m<=10000;
	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
*/
#include<iostream>
using namespace std;
const int N = 100010;
int a[N], b[N];
int n, m,i,l,r,c;
// 核心算法
void insert(int l, int r, int c) {
	b[l] += c;
	b[r+1] -= c;
}
int main(){
	scanf_s("%d%d", &n, &m);

	for (i = 1; i <= n; i++)
		scanf_s("%d", &a[i]);

	for (i = 1; i <= n; i++)
		insert(i, i, a[i]);	// 得到原来b序列

	while (m--) {
		scanf_s("%d%d%d", &l, &r, &c);
		insert(l, r, c);
	}

	for (i = 1; i <= n; i++)
		b[i] += b[i - 1];
	for (i = 1; i <= n; i++)
		printf("%d ", b[i]);

    return 0;
}

 二维差分

在这里插入图片描述

 例题

/*
	输入:一个n*m的整数矩阵 再输入q个操作包括五个整数x1,y1,x2,y2,c;
	其中(x1,y1)和(x2,y2)表示一个子矩阵的左上角坐标和右下角坐标
	每个操作要把选中的子矩阵中的每个元素的值都加上c
	输入格式:
	第一行: n,m,q
	n行:每行包含m个整数,表示整数矩阵
	输出格式:
	共n行,每行m个整数,表示所有操作进行完毕后的最终矩阵。
	数据范围:
	1<=n,m<=1000
	1<=q<=100000
	1<=x1<=x2<=n
	1<=y1<=y2<=m
	输入样例:
		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
*/
#include<iostream>
using namespace std;
const int N = 1010;
int a[N][N], b[N][N];
int n, m, q,i,j;

// 核心算法
void insert(int x1, int y1, int x2, int y2, int c) {
	b[x1][y1] += c;
	b[x2 + 1][y1] -= c;
	b[x1][y2 + 1] -= c;
	b[x2 + 1][y2 + 1] += c;
}

int main() {
	scanf_s("%d%d%d", &n, &m, &q);

	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
			scanf_s("%d", &a[i][j]);

	for (i = 1; i <= n; i++)
		for (j = 1; j <= m; j++)
			insert(i, j, i, j, a[i][j]);

	int x1, y1, x2, y2,c;
	while (q--) {
		scanf_s("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
		insert(x1, y1, x2, y2, c);
	}
	
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] ;

	for (i = 1; i <= n; i++) {
		for (j = 1; j <= m; j++) {
			printf("%2d ", b[i][j]);
		}
		printf("\n");
	}
    return 0;
}
  • 14
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sumpon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值