【模板】树状数组 1
题目描述
如题,已知一个数列,你需要进行下面两种操作:
-
将某一个数加上
x
-
求出某区间每一个数的和
输入格式
第一行包含两个正整数 n,m
,分别表示该数列数字的个数和操作的总个数。
第二行包含 n
个用空格分隔的整数,其中第 i
个数字表示数列第 i
项的初始值。
接下来 m
行每行包含 3
个整数,表示一个操作,具体如下:
-
1 x k
含义:将第x
个数加上k
-
2 x y
含义:输出区间[x,y]
内每个数的和
输出格式
输出包含若干行整数,即为所有操作 2
的结果。
样例 #1
样例输入 #1
5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
样例输出 #1
14
16
提示
【数据范围】
对于 30%
的数据,1 ≤ n ≤ 8
,$1 ≤ m ≤ 10
;
对于 70%
的数据,1 ≤ n,m ≤ 10^4
;
对于 100%
的数据,1 ≤ n,m ≤ 5 * 10^5
。
数据保证对于任意时刻,a
的任意子区间(包括长度为 1
和 n
的子区间)和均在 [-2^{31}, 2^{31})
范围内。
样例说明:
故输出结果14、16
思路:树状数组?线段树?
三步走!!!
-
建树
void buildtree(int k,int l,int r){ if(l==r){ //l==r时就是分到只剩一个了 f[k]=a[l];//此时返回叶子结点数据(也就是原数据) return; } //以下三步,就是找左右儿子 //这个过程与归并排序的递归过程类似可以去看一下 //其中2k和2k+1代表的是当前结点的左右子结点(这一步不详细展开,可以自己画图尝试) int mid=(l+r)>>1; buildtree(2*k,l,mid); buildtree(2*k+1,mid+1,r); //父亲结点=儿子结点的和 f[k]=f[2*k]+f[2*k+1]; }
-
修改数据
void add(int k,int l,int r,int x,int y){ //k表示第几个结点,l、r表示区间,x表示第几个值要修改,y表示要使原值+y //因为每次找到的都是第x个元素的父亲结点的父亲的父亲……所以直接+y f[k]+=y;//包含结点x的值都需要+y if(