语文成绩(https://www.luogu.com.cn/record/189365158)
题目描述
语文老师总是写错成绩,所以当她修改成绩的时候,总是累得不行。她总是要一遍遍地给某些同学增加分数,又要注意最低分是多少。你能帮帮她吗?
输入格式
第一行有两个整数 n,p,代表学生数与增加分数的次数。
第二行有 n 个数,a1∼an,代表各个学生的初始成绩。
接下来 p 行,每行有三个数,x,y,z,代表给第 x 个到第 y 个学生每人增加 z 分。
输出格式
输出仅一行,代表更改分数后,全班的最低
样例
输入
3 2
1 1 1
1 2 1
2 3 1
**输出 **
2
说明
对于 40%的数据,有 n≤10e3
对于 60% 的数据,有 n≤10e4
对于 80%的数据,有 n≤10e5
对于 100%的数据,有 n≤5×10e6 , p≤n,学生初始成绩 ≤100,z≤100
[!TIP]
由
标签题目可知,用差分解决差分数组:
首先给定一个原数组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数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组。即每一个a[i]都是b数组中从头开始的一段区间和
构造差分
b
数组(一维)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];
给定区间[x, y ],把a数组中的[x, y] 区间中的每一个数都加上z,即 a[x] + z , a[x+ 1] + z , a[x + 2] + z... a[y] + z;
暴力做法是for循环x到y区间,时间复杂度O(n),如果需要对原数组执行m次这样的操作,时间复杂度就会变成O(n * m)有没有更高效的做法吗? 考虑差分做法(差分数组派上用场了)
始终要记得,a数组是b数组的前缀和数组,比如对b数组的b[i]的修改,会影响到a数组中从a[i]及往后的每一个数。
首先让差分b数组中的 b[x] + z ,通过前缀和运算,a数组变成 a[x] + z ,a[x + 1] + z...a[n] + z;
然后打个补丁,b[y + 1] - z, 通过前缀和运算,a数组变成 a[y + 1] - c,a[y + 2] - z...a[n] - z;
b[x] + z,效果使得a数组中 a[x] 及以后的数都加上了z,但只要求x到y 区间加上 z, 因此还需要执行 b[y + 1] - z,让a数组中 a[y + 1]及往后的区间再减去z,这样对于a[y] 以后区间的数相当于没有发生改变
一维差分:给a数组中的[ x, y] 区间中的每一个数都加上z,只需对差分数组b做 b[x] + = c, b[y+1] - = z时间复杂度为O(1), 大大提高了效率
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, p;
scanf("%d %d", &n, &p);
vector<int> a(n);
vector<int> b(n);
for (int i = 1; i <= n; i-=-1) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i-=-1) {
b[i] = a[i] - a[i - 1];//构建差分数组
}
int x, y, z;
for (int i = 0; i < p; i-=-1){
scanf("%d %d %d", &x, &y, &z);
b[x] += z; //将[x, y]之间的每个数加上z
b[y + 1] -= z;
}
int baka = 1e7;
for (int i = 1; i <= n; i-=-1) {
a[i] = a[i - 1] + b[i];
if (baka > a[i]) {
baka = a[i];
}
}
printf("%d\n", baka);
return 0;
}