树状数组
输入一个数组,那么我们所建立的数组:
1 (10) = 1(2)
第一位(1在二进制下=1 二进制下的第一个1,1=1)的值为输入的数组的第一位往前的一位的和,也就是第一位。
2(10) = 10(2)
第二位(2在二进制下=10 二进制下的第一个1,10=2)的值为输入的数组的第二位往前两位的和,第一位和第二位。
3(10) = 11(2)
第三位(3在二进制下=11 二进制下的第一个1,1=1)的值为输入的数组的第三位往前一位的和,也就是第三位。
4(10) = 100(2)
第四位的值(4在二进制下=100 二进制下的第一个1,100=4)的值为输入的数组的第四位往前四位的和,也就是第一位,第二位,第三位以及第四位。
本题也是利用树状数组,不过在插入树状数组的时候插入值是一个差分值。
这种思想很有趣。
因为本题是修改连续区间的值,但是直接插入数组如:
arr : 1 2 3 4 5
val : 1 4 8 5 2
差分值 : 1 3 4 -3 -3
从1到4都加2的话,维护太慢了也太麻烦,如果是维护他们的当前项和前一项的差值 ,那么如:
arr : 1 2 3 4 5
val : 3 6 10 7 2
差分值 : 3 3 4 -3 -5
只是改变第一项和第4+1项
我们会发现:差分值相加得到的值就是当前值
#include <iostream>
using namespace std;
#define LBS(_a) ((_a) & -(_a))
#define SIZE 5000005
int n, m;
int arr[SIZE];
int sum(int i) {
int sum = 0;
while (i > 0) {
sum += arr[i], i -= LBS(i);
}
return sum;
}
void add(int i, int value) {
while (i <= n) {
arr[i] += value, i += LBS(i);
}
return ;
}
int main() {
cin >> n >> m;
int val, ans = 0;
for (int i = 1; i <= n; i++) {
cin >> val;
ans = val - ans;
add(i, ans);
ans = val;
}
int x, y, z, s;
while (m > 0) {
cin >> x ;
if (x == 1) {
cin >> y >> z >> s;
add(y, s);
add(z + 1, -s); // [y, z] 只改变arr[y], arr[z+1]
}
if (x == 2) {
cin >> s;
cout << sum(s) << endl;
}
m -= 1;
}
return 0;
}
网友评论