【模板】树状数组 2 - 区间操作&元素求值
题目描述
如题,已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数数加上
x
; - 求出某一个数的值。
输入格式
第一行包含两个整数N
、M
,分别表示该数列数字的个数和操作的总个数。
第二行包含N
个用空格分隔的整数,其中第i
个数字表示数列第i
项的初始值。
接下来M
行每行包含2
或4
个整数,表示一个操作,具体如下:
- 操作
1
:格式:1 x y k
含义:将区间[x,y]
内每个数加上k
; - 操作
2
:格式:2 x
含义:输出第x
个数的值。
输出格式
输出包含若干行整数,即为所有操作2
的结果。
输入输出样例
输入 | 输出 |
---|---|
5 5 1 5 4 2 3 1 2 4 2 2 3 1 1 5 -1 1 3 5 7 2 4 | 6 10 |
说明/提示
样例1解释:
故输出结果为6
、10
。
数据规模与约定
对于30%
的数据:N≤8
,M≤10
;
对于70%
的数据:N≤10000
,M≤10000
;
对于100%
的数据:1≤N,M≤500000
,1≤x
,y≤n
,保证任意时刻序列中任意元素的绝对值都不大于2E30
。
思想
引用:题解 P3368 【模板】树状数组 2】 - Lyp10000 的博客 - 洛谷博客
设数组
a[]
={1,6,8,5,10}
,那么差分数组b[]
={1,5,2,-3,5}
也就是说
b[i]
=a[i]
-a[i-1]
, (a[0]
= 0),那么a[i]
=b[1]
+...
+b[i]
。假如区间[2,4]都加上2的话
a[]
数组变为{1,8,10,7,10}
b[]
数组变为{1,7,2,-3,3}
b[]
数组只有b[2]
和b[5]
变了,因为区间[2,4]是同时加上2的,所以在区间内b[i]
-b[i-1]
是不变的.所以对区间[x,y]进行修改,只用修改
b[x]
与b[y+1]
:
b[x]
=b[x]
+k
b[y+1]
=b[y+1]
-k
代码
#include <cstdio>
typedef int datatype;
struct bintree_base
{
//树状数组指针
datatype *a;
//元素数量
int n;
//初始化
explicit bintree_base(const int &_n){
n = _n;
a = new datatype[n + 1]();
}
~bintree_base(){
delete[] a;
}
datatype lowbit(const datatype &num){
return num & (-num);
}
//求从1到index的和
datatype accumulate(int index){
datatype ans = 0;
while (index)
ans += a[index], index -= lowbit(index);
return ans;
}
//求区间和
datatype accumulate(const int &begin, const int &end){
return accumulate(end) - accumulate(begin - 1);
}
//在index位置上+value并更新到树上
void add(int index, const datatype &value){
while (index <= n)
a[index] += value, index += lowbit(index);
}
};
//差分树状数组,继承自基本树状数组
struct bintree_diff : public bintree_base
{
protected:
typedef bintree_base super;
public:
explicit bintree_diff(const int &_n) : super(_n){};
//更改某一位置的某个值
void assign(int index, const datatype &value){
add(index, index + 1, -super::accumulate(index));
add(index, index + 1, value);
}
//在[head,tail)区间+value
void add(int head, int tail, datatype value){
super::add(head, value);
super::add(tail, -value);
}
//index位置的值
datatype at(const int &index){
return super::accumulate(index);
}
};
int main(){
int n, m, tmp1, tmp2 = 0, tmp3, tmp4;
scanf("%d%d", &n, &m);
bintree_diff bt(n);
for (int i = 1; i <= n; ++i){
scanf("%d", &tmp1);
bt.assign(i, tmp1);
}
for (int i = 0; i < m; ++i){
scanf("%d", &tmp1);
switch (tmp1){
case 1:
scanf("%d%d%d", &tmp2, &tmp3, &tmp4);
//左闭右开,tmp3+1
bt.add(tmp2, tmp3 + 1, tmp4);
break;
case 2:
scanf("%d", &tmp2);
printf("%d\n", bt.at(tmp2));
break;
}
}
return 0;
}