語文成績(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;
}