树状数组基本模板

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

 

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

 1 int lowbit(int x){return x&(-x);}  2 //lowbit函数,决定下一个/上一个覆盖区间

 3 

 4 void add(int x,int a){  5     for(int i=x;i<=N;i+=lowbit(i))c[i]+=a;  6 }  7 //单点加数

 8 

 9 int sum(int x){ 10     int ans=0; 11     for(int i=x;i>0;i-=lowbit(i))ans+=c[i]; 12     return ans; 13 } 14 //区间求和

 

区间求最值功能:

 1 int lowbit(int x){return x&(-x);}  2 

 3 void init(int n){  4     for(int i=1;i<=n;i++){  5         ma[i]=a[i];  6         for(int j=1;j<lowbit(i);j<<=1)  7             ma[i]=max(ma[i],ma[i-j]);  8  }  9 } 10 //init函数是构建最大值数组的函数,其中 n 是数组长度,a 是原数组,ma 是区间最大值数组,表示 [ i - lowbit [ i ] ,i ]区间内的最大值,对于每一个 i ,用被其覆盖的各个区间的最大值更新它。

11 

12 int query(int l,int r){ 13     int ans=a[r]; 14     while(1){ 15         ans=max(ans,a[r]); 16         if(l==r)break; 17         for(r-=1;r-l>=lowbit(r);r-=lowbit(r)) 18             ans=max(ans,ma[r]); 19  } 20     return ans; 21 } 22 //查询 [ l , r ] 区间内的最大值,通过不断考虑 r 覆盖的区间中的最大值,将 r 不断左移直到等于 l ,返回这中间的最大值,对于每一次遍历的 r ,若 r 覆盖的区间在查询区间内,就直接使用该区间的最大值,然后左移 r 值原先 r 覆盖的区间左,若 r 覆盖的区间比查询区间大,就直接考虑 r 的值,然后将 r 左移至 k - 1 ;这样循环直到 l == r 。

 

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

 

 1 int lowbit(int x){return x&(-x);}  2 

 3 void change(int x,int v){  4     while(x<=n){    //n是树状数组长度

 5         c[x]+=v;  6         x+=lowbit(x);  7  }  8 }  9 

10 int sum(int x){    //求x单点值

11     int s=0; 12     while(x){ 13         s+=c[x]; 14         x-=lowbit(x); 15  } 16     return s; 17 } 18 

19 void update(int l,int r,int v){    //将区间[l,r]加v

20  change(l,v); 21     change(r+1,-v); 22 }

 

你可能感兴趣的:(树状数组)