树状数组
首先,先讲一讲什么是树状数组。
(下面一段,引用至百度百科)
树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。

假设数组a[1..n],那么查询a[1]+...+a[n]的时间是log级别的,而且是一个在线的数据结构,支持随时修改某个元素的值,复杂度也为log级别。
来观察这个图:
令这棵树的结点编号为C1,C2...Cn。令每个结点的值为这棵树的值的总和,那么容易发现:C1 = A1C2 = A1 + A2C3 = A3C4 = A1 + A2 + A3 + A4C5 = A5C6 = A5 + A6C7 = A7C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8...C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16这里有一个有趣的性质:设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,所以很明显:Cn = A(n – 2^k + 1) + ... + An
所以首先,定义一个名叫lowbit的函数。
#define lowbit(x)(x&(-x))
//#define lowbit(x)(x&(x^(x–1))
看了代码,咱们再来讲讲,lowbit用来干啥。
&,是位运算与,通常用于二进制取位操作,例如一个数 &1的结果就是取二进制的最末位。
我们假设x=10(10进制),它的二进制是001010。而-x(-10)的二进制就是把它的0变成1,1变成0,末尾再加1,等于110110。001010 & 110110 = 000010
所以,lowbit的作用是求出m的二进制表示的末尾1的位置。
接下来,我们定义一个add函数。add函数用来维护数组。
void add(int x,int y){
while(x<=n){
a[x]+=y;
x+=lowbit(x);
}
}
add函数是将数组的第x位加y,并维护数组。
能改变还不够,我们还要能求和。所以我们定义一个sum函数,用来求前x项的和。
int sum(int x){
int ans=0;
while(x>0){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
但是,这只是求前x项的和,要是要求x到y的和,该怎么办呢?
没事,只要求出前y项的和,再减去x,就行了。
下面是完整的代码:
1 #include<bits/stdc++.h>
2 #define lowbit(x) (x&(-x))
3 using namespace std;
4
5 int a[500001];
6 int n,m;
7
8 void add(int x,int y){
9 while(x<=n){
10 a[x]+=y;
11 x+=lowbit(x);
12 }
13 }
14 int sum(int x){
15 int num=0;
16 while(x>0){
17 num+=a[x];
18 x-=lowbit(x);
19 }
20 return num;
21 }
22
23 int main(){
24 cin>>n>>m;
25 int x,y,z;
26 for(int i=1;i<=n;i++){cin>>x;add(i,x);}
27 for(int i=1;i<=m;i++){
28 cin>>x>>y>>z;
29 if(x==1)add(y,z);
30 else cout<<sum(z)-sum(y-1)<<endl;
31 }
32 }
这是我的第一篇博客,有不好之处,尽请谅解。

浙公网安备 33010602011771号