題目描述
Thanks to everyone’s help last week, TT finally got a cute cat. But what TT didn’t expect is that this is a magic cat.
One day, the magic cat decided to investigate TT’s ability by giving a problem to him. That is select n cities from the world map, and a[i] represents the asset value owned by the i-th city.
Then the magic cat will perform several operations. Each turn is to choose the city in the interval [l,r] and increase their asset value by c. And finally, it is required to give the asset value of each city after q operations.
Could you help TT find the answer?
輸入
The first line contains two integers n,q (1≤n,q≤2⋅105) — the number of cities and operations.
The second line contains elements of the sequence a: integer numbers a1,a2,…,an (−106≤ai≤106).
Then q lines follow, each line represents an operation. The i-th line contains three integers l,r and c (1≤l≤r≤n,−105≤c≤105) for the i-th operation.
輸出
Print n integers a1,a2,…,an one per line, and ai should be equal to the final asset value of the i-th city.
樣例輸入
4 2
-3 6 8 4
4 4 -2
3 3 1
樣例輸出
-3 6 9 2
思路
綜述
這道題主要考察了一個新的方法:差分
針對兩個數組而言,設原數組A和差分數組B數組;範圍:[1,n]
滿足:
1)B[1] = A[1];
2)B[i] = A[i] - A[i-1];
所以有如下性質:
1)B的數組前綴和 == A數組的元素值
SUM{B[1~i]} = A[i]
2)A 數組的區間加 == B數組的單點修改
A[L]~A[R] 均加上c
等於 B[L]+=c B[R+1]-=c;
過程
結構體:
開大數組來存儲每一個矩形。
struct node {
long long value;
long long l;//存左側編號
long long r;//存右側編號
long long number;//編號
};
node Node[100010];
Step1:輸入
構建兩個數組
for (long long i = 1; i <= n; i++) {
cin >> a[i];
}
b[1] = a[1];
for (long long i = 2; i <= n; i++) {
b[i] = a[i] - a[i - 1];
}
Step2:操作A數組 => 操作B數組
按照性質進行操作
只有一點需要注意:
當 操作的是A數組的最後一個元素值的時候,不需要操作B[R+1]-=C
此時B數組越界,而且這時只需要B[L]+=c;
for (long long i = 0; i < q; i++) {
cin >> L >> R;
cin >> c;
b[L] += c;
if (R != n)
b[R + 1] -= c;
}
總結
1、本題中與A題一樣也是要考慮數據範圍的問題,
1)這裏初始化時,最大是106;
2)操作的個數是105;
3)每次操作的數值最大是105,
如果用int可能會精度不夠
int的範圍是-2147483648~2147483647
2、雖然A數組和差分數組有關係
A 數組的區間加 == B數組的單點修改
但是操作A數組區間時,如果操作到A數組的最後一個位置,這時,只需要操作B數組的區間左端點。
代碼
#include <iostream>
#include <stack>
using namespace std;
struct node {
long long value;
long long l;
long long r;
long long number;
};
node Node[100010];
int main() {
long long n;
while (1) {
cin >> n;
if (n == 0)break;
stack<node> S;
for (long long i = 0; i < n; i++) {
cin >> Node[i].value;
Node[i].number = i;
}
//確定右端點
for (long long i = 0; i < n; i++) {
//如果棧空,直接push
if (S.empty()) {
S.push(Node[i]);
}
else {
//如果棧非空,則將棧內每一個比當前元素值小的值都pop
while (!S.empty() && S.top().value > Node[i].value) {
//pop出來的同時,對出棧的矩形記錄右端點的值
Node[S.top().number].r = i;
S.pop();
}
S.push(Node[i]);
}
}
//遍歷完一遍之後,對棧內所有的元素,其右端點都是n
while (!S.empty()) {
Node[S.top().number].r = n;
S.pop();
}
//確定左端點
//與確定右端點類似,只不過方向相反
for (long long i = n - 1; i >= 0; i--) {
if (S.empty()) {
S.push(Node[i]);
}
else {
while (!S.empty() && S.top().value > Node[i].value) {
Node[S.top().number].l = i;
S.pop();
}
S.push(Node[i]);
}
}
while (!S.empty()) {
Node[S.top().number].l = -1;
S.pop();
}
long long tot = -10000;
for (long long i = 0; i < n; i++) {
if (Node[i].value * (Node[i].r - Node[i].l - 1) > tot)
tot = Node[i].value * (Node[i].r - Node[i].l - 1);
}
cout << tot << endl;
}
}