树状数组可以很方便地实现数组的动态修改求和,并且代码量非常小!经过拓展之后,还可以实现区间修改单点查询、求区间最值和第 K 大值(继续学习之后再更新)

 

基本功能的实现主要有三个函数,lowbit 、 add 、 getsum;

单点加值区间求和:

 

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 const int maxn=1e5+5;        //数组大小
 5 
 6 int c[maxn];
 7 
 8 void init(){
 9     memset(c,0,sizeof(c));
10 }
11 
12 inline int lowbit(int x){return x&(-x);}
13 //lowbit函数,决定下一个/上一个覆盖区间
14 
15 void add(int x,int a,int n){
16     for(int i=x;i<=n;i+=lowbit(i))c[i]+=a;
17 }
18 //单点加数
19 
20 int sum(int x){
21     int ans=0;
22     for(int i=x;i>0;i-=lowbit(i))ans+=c[i];
23     return ans;
24 }
25 //区间求和

  

 

动态单点更新并区间求最值功能:

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 const int maxn=1e5+5;        //数组大小
 5 inline int lowbit(int x){return x&(-x);}
 6 inline int max(int a,int b){return a>b?a:b;}
 7 int a[maxn],ma[maxn];        //a为原数组,ma为最大值数组
 8 
 9 void init(int n){
10     for(int i=1;i<=n;i++){
11         ma[i]=a[i];
12         for(int j=1;j<lowbit(i);j<<=1)
13             ma[i]=max(ma[i],ma[i-j]);
14     }
15 }
16 //init函数是构建最大值数组的函数,其中 n 是数组长度,a 是原数组,ma 是区间最大值数组,表示 [ i - lowbit [ i ]  ,i ]区间内的最大值,对于每一个 i ,用被其覆盖的各个区间的最大值更新它。
17 
18 void change(int ind,int v,int n){
19     a[ind]=v;
20     for(int i=ind;i<=n;i+=lowbit(i)){
21         ma[i]=v;
22         for(int j=1;j<lowbit(i);j<<=1)
23             ma[i]=max(ma[i],ma[i-j]);
24     }
25 }
26 //将第ind个数更新为v
27 
28 int query(int l,int r){
29     int ans=a[r];
30     while(1){
31         ans=max(ans,a[r]);
32         if(l==r)break;
33         for(r-=1;r-l>=lowbit(r);r-=lowbit(r))
34             ans=max(ans,ma[r]);
35     }
36     return ans;
37 }
38 //查询 [ l , r ] 区间内的最大值,通过不断考虑 r 覆盖的区间中的最大值,将 r 不断左移直到等于 l ,返回这中间的最大值,对于每一次遍历的 r ,若 r 覆盖的区间在查询区间内,就直接使用该区间的最大值,然后左移 r 值原先 r 覆盖的区间左,若 r 覆盖的区间比查询区间大,就直接考虑 r 的值,然后将 r 左移至 k - 1 ;这样循环直到 l == r 。

 

 

树状数组还有区间加值单点查询的功能:

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 const int maxn=1e5+5;        //数组大小
 5 
 6 int c[maxn];
 7 
 8 inline int lowbit(int x){return x&(-x);}
 9 
10 void change(int x,int v,int n){
11     while(x<=n){
12         c[x]+=v;
13         x+=lowbit(x);
14     }
15 }
16 
17 int sum(int x){                        //求x单点值
18     int s=0;
19     while(x){
20         s+=c[x];
21         x-=lowbit(x);
22     }
23     return s;
24 }
25 
26 void update(int l,int r,int v){        //将区间[l,r]加v
27     change(l,v);
28     change(r+1,-v);
29 }