差分法思想
如果我们想将红色框选区间(数组对应下标为2至5)数据全部加1。只需要将下标为2的差分数组的数据加一,将下标为6的差分数组的数据减一。
如果我们想将绿色框选区间(数组对应下标为0至3)数据全部加2。只需要将下标为0的差分数组的数据加2,将下标为4的差分数组的数据减2。
我们可以总结出规律:
我们想要让num数组i到j的数据都加n,需要其差分数组defferNum[ i ]+=n, defferNum[j+1] -= n,
有了差分法思想,当然要实践啊
例题
语文老师总是写错成绩,所以当她修改成绩的时候,总是累得不行。
她总是要一遍遍地给某些同学增加分数,又要注意最低分是多少。你能帮帮她吗?
输入格式
第一行,两个整数n,m,代表学生总数和增加分数的次数。
第二行,n个整数,代表每个学生的初始成绩。
接下来m行,每行有三个整数x,y,z,代表给第x个到第y个学生每人增加z分。
输出格式
输出仅一行,代表更改分数后,全班的最低分。
数据范围
1 ≤ n ≤ 1, 000, 000,m ≤ n,学生初始成绩 ≤ 100,z ≤ 100(成绩可以大于100)
输入数据 3 2
1 1 1
1 2 1
2 3 1
输出数据 2
如果暴力求解,将数组区间用for循环遍历加一,但是如果我们的n足够大, 逼如恰好等于1, 000, 000,则需要遍历1000000次,一定是超时的。
#include <stdio.h>
#include <limits.h>//INT_MAX关键字的头文件
int num[1000010]; //成绩
int differ[1000010]; //差分数组
int main()
{
int n, m, min = INT_MAX;//INT_MAX是整形的最大值,
//因为成绩是可以很大的,我们需要将min赋最大值,为后面作比较
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", &num[i]);
if (i == 0) differ[i] = num[i]; //第一个数直接赋值
differ[i] = num[i] - num[i - 1];
}
while (m--) {
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
differ[x - 1] += z;
if (y < n) { //考虑极端情况
differ[y] -= z;
}
}
//还原
num[0] = differ[0];//o下标需要直接赋值
if (num[0] < min)//将num[0]与min作比较
min = num[0];
for (int i = 1; i < n; i++) {
num[i] = differ[i] + num[i - 1];
if (num[i] < min) {
min = num[i];
}
}
printf("%d", min);
return 0;
}