差分算法及代码模版(c++)

1、一维差分

1、基本思想

首先定义数组a[] , 其中a[1],a[2]…a[n]作为前缀和。

然后通过a数组来构造数组b,b[1],b[2]…b[n]为差分数组。使得可以通过差分数组的前缀和来表示a数组,即a[i] = b[1] + b[2]+…+b[i]。

构造方式为b[1] = a[1], b[2] = a[2] - a[1], b[n] = a[n] - a[n-1];

得到的关系是:b数组就称为a数组的差分,a数组称为b的前缀和。

2、好处

差分数组的好处是可以简化运算,例如想要给一个区间 [l,r] 上的数组加一个常数c,原始的方法是依次加上c,这样的时间复杂度是O(n)的。但是如果采用差分数组的话,可以大大降低时间复杂度到O(1)。

3、用处

想要在[l,r]区间内的数据同时加一个常数c, 由于a[n] = b[1] + b[2]+…+b[n],因此只需要将b[l] = b[l] + c 即可,这样l之后的数字会依次加上常数c,而在 b[r]处,将b[r+1] = b[r+1] - c ,这样r之后的数组又会恢复原值,仅需要处理这两个边界的差分数组即可,时间复杂度大大降低。

4、代码

假定a数组全部都为0,那么差分数组b也就全为0,

第一次是让原数组中[1,1]区间加上a[1]

第二次是让原数组中[2,2]区间加上a[2]

总结出来 差分就只有一个操作:

如果想给区间[l,r] +c

b[l] +c b[r+1] -c

例题:差分
输入一个长度为 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

#include <iostream>

using namespace std;

const int N = 100010;
int n, m;
int a[N], b[N];

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]);
	//初始化b数组
	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);
		//表示将序列中 [l,r] 之间的每个数加上 c
		insert(l,r, c);
	}
    
	//b数组的前缀和就是a数组
	for (int i = 1; i <= n; i++) b[i] = b[i - 1] + b[i];

	for (int i = 1; i <= n; i++) printf( "%d",b[i]);
	return 0;
}

2、二维差分

1、引言:

首先定义一下:

将a[i][j]表示为一个差分数列b[i][j]的和

即a[i][j]存的是[i,j]左上角所有b[i][j]的和
在这里插入图片描述

2、基本思路:

给中间的小矩形加上常量c :

给其中的一个子矩阵加上一个值。矩阵以外的减去一个值即可。

3、解释:

b[x1][y1] += c; => 因为a数组是b数组的前缀和,所以 [x1][y1]的右下角全部都加上c

在这里插入图片描述

由上面范围,可以求得最终要算的小正方形的面积公式。

矩阵的初始化;

假定a[i][j] = 0,那么b[i][j] =0,然后读取数组a,只需要对b进行插入即可。b[i][j]相当于从(i,j)到(i,j)插入一个a[i][j]形成的。

最后求a[i][j]只需要求解b[i][j]的前缀和即可。

4、例题:差分矩阵

输入一个 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

代码
#include <iostream>

using namespace std;

int n, m, q;
const int N = 1010;

int a[N][N], b[N][N];

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",&a[i][j]);

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

	while (q --)
	{
		int x1, y1, x2, y2, c;
		cin >> 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 - 1][j] + b[i][j - 1] - b[i - 1][j - 1];

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
			printf("%d ",b[i][j]);
		puts("");
	}
		

	return 0;
}
  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 好的,以下是一个简单的 C 差分模板: #include <stdio.h> int main() { int n; scanf("%d", &n); int a[n], d[n]; for (int i = ; i < n; i++) { scanf("%d", &a[i]); } d[] = a[]; for (int i = 1; i < n; i++) { d[i] = a[i] - a[i-1]; } for (int i = ; i < n; i++) { printf("%d ", d[i]); } return ; } 希望对你有所帮助! ### 回答2: 差分是一种常见的算法,在竞赛和科学计算中经常用到。下面是一个简单的C语言差分模板示例: ```c #include <stdio.h> #define MAXN 1000 int diff[MAXN]; void update(int l, int r, int val) { diff[l] += val; diff[r + 1] -= val; // 注意需要累计到r+1的位置 } void rebuild(int n, int arr[]) { for (int i = 1; i <= n; i++) { if (i == 1) { arr[i] = diff[i]; } else { arr[i] = arr[i - 1] + diff[i]; } } } int main() { int n, m; int arr[MAXN]; // 输入数组的大小和操作的个数 scanf("%d %d", &n, &m); // 输入原始数组的值 for (int i = 1; i <= n; i++) { scanf("%d", &arr[i]); } // 执行m个操作 for (int i = 1; i <= m; i++) { int l, r, val; scanf("%d %d %d", &l, &r, &val); update(l, r, val); } // 重新构建数组 rebuild(n, arr); // 输出结果 for (int i = 1; i <= n; i++) { if (i == 1) { printf("%d", arr[i]); } else { printf(" %d", arr[i]); } } printf("\n"); return 0; } ``` 该差分模板中,首先定义了一个差分数组`diff`,用于存储每个位置的累计差值。接着定义了`update`函数,用于更新差分数组的某个区间的差值。最后定义了`rebuild`函数,根据差分数组重新构建原始数组。在`main`函数中,首先输入原始数组,然后执行m个操作,每个操作会更新差分数组,最后根据差分数组重新构建并输出原始数组。这个模板可以用于解决一些区间更新的问题,如区间加法、区间减法等。 ### 回答3: 差分模板是一种常用的算法,用于快速求解给定数组中元素之间的差异。以下是一个简单的C语言差分模板的示例: ```c #include <stdio.h> // 数组长度 #define MAX_N 100 // 原始数组 int arr[MAX_N]; // 差分数组 int diff[MAX_N]; // 更新差分数组 void updateDiff(int l, int r, int val) { diff[l] += val; diff[r + 1] -= val; } // 获取最终数组 void getFinalArray() { arr[0] = diff[0]; for (int i = 1; i < MAX_N; i++) { arr[i] = arr[i - 1] + diff[i]; } } int main() { // 初始化原始数组 for (int i = 0; i < MAX_N; i++) { arr[i] = 0; } // 对原始数组进行操作 updateDiff(1, 3, 2); updateDiff(2, 5, 3); updateDiff(0, 2, 1); // 获取最终数组 getFinalArray(); // 打印最终数组 for (int i = 0; i < MAX_N; i++) { printf("%d ", arr[i]); } return 0; } ``` 在这个示例中,我们使用了两个数组:`arr`用于表示原始数组,`diff`用于表示差分数组。`updateDiff`函数用于更新差分数组过程中的差值,`getFinalArray`函数用于计算最终的数组。通过对原始数组进行一系列操作(以示例中的操作为例),我们可以通过差分数组计算出最终的数组。最后,我们打印最终数组的结果。 请注意,这只是一个简单的差分模板示例,实际应用中可能需要更多的逻辑和操作。根据具体需求,你可以根据这个模板进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

少年负剑去

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

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

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

打赏作者

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

抵扣说明:

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

余额充值