给一个数组,每次对某个区间增加某个值,如何在线性时间内完成。
比如一个数组,刚开始都是0吧,如下表,第一行是下标:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
操作 1 3 5,代表给下标1-3的元素都加5,有很多次这样的操作。
正常来说,这个算法复杂度为n^2。
要实现线性时间,就只能通过某种记录方式,然后再通过记录,还原出最后的数据。
我们开辟一个csum数组,对每一波操作(left, right, value)有:
csum[left -1] -= value;
csum[right] += value;
然后对每一对三元操作都以同样的方式记录。
例如1 3 5操作完成后,csum数组为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
-5 | 0 | 0 | 5 | 0 | 0 | 0 | 0 |
最后按照如下方式还原:
x[i] = x[i + 1] + csum[i];
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | 5 | 5 | 5 | 0 | 0 | 0 | 0 |
就得到了区间修改后的数组。
完整代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
vector<int> nums, csum;
const int NUMS = 10;
const int NINTERVAL = 3;
int main(){
freopen("in.txt", "r", stdin);
int value = 4;
for (int i = 0; i < NUMS + 1; ++i){
nums.push_back(0);
csum.push_back(0);
}
int leftV[NINTERVAL] = {2, 3, 7};
int rightV[NINTERVAL] = {4, 6, 9};
for (int i = 0; i < NINTERVAL; ++i){
if (leftV[i] - 1 >= 0){
csum[leftV[i] - 1] -= value;
}
csum[rightV[i]] += value;
}
for (int i = NUMS - 1; i >= 0; --i){
nums[i] = nums[i + 1] + csum[i];
}
for (int i = 0; i < NUMS; ++i){
cout << nums[i] << endl;
}
return 0;
}