ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

数据结构--树状数组

2021-05-28 09:32:32  阅读:233  来源: 互联网

标签:单点 覆盖 树状 -- lowbit int 区间 数据结构 任意


证明参考:https://zhuanlan.zhihu.com/p/297885717(抄的)

树状数组支持的操作:单点修改,区间查询(仅限于支持减法的操作,不支持的例子:max)

树状数组定义:定义C[ i ] 表示的是A [ i - lowbit(i) ] + 1  ~~   A[ i ] 之间的数据。

C[ i ]的父节点为C[ i + lowbot ( i ) ]

C[ i ]的子节点有C[ i - lowbit(i) ] , C[i - lowbit(i) -lowbit ( i - lowbit ( i ) ) ].........

 

术语定义:对于一个点 i ,其覆盖的点的左端点记为L(i) , L(i) = i - lowbit( i )

     对于任意正整数x,x=a*2^(i+1) + 2^i,其中a>=0,i>=0,则lowbit(x)=2^i

要证:(1)x+lowbit(x)能够覆盖x

   (2)x~x+lowbit(x)之间不存在能够覆盖x的数

    那么 i 的父节点是 i+lowbit(i) 得证。   

   (3)1<=x<=y<=z,y覆盖x,z覆盖y,那么z覆盖x

   (4)对于一个数x,覆盖的数有且仅有x , x-lowbit(x) , x-lowbit(x) - lowbit( x-lowbit(x) ).....

    那么 i 的子节点得证。

    【分析】因为具有传递覆盖的性质,且x覆盖的区间的并集是1~x,故得证。

证明:(1)设x=a*2^(i+1)+2^i,则y=x+lowbit(x) = a*2^(i+1)+2^i+2^i = (a+1)*2^(i+1)

     所以 lowbit(y) >= 2^(i+1) 

     x-L(y) = x  - (x+lowbit(x) - lowbit(y) +1)

        =lowbit(y) - lowbit(x) - 1

        >=2^(i+1)-2^i - 1 

        =2^i - 1 >= 0

    故L(y)>=x,即y覆盖x,C[ i+lowbit(i) ]确实可以完全覆盖 C[ i ]

    (2)设x<y,要证明对于任意的x<z<y,z不覆盖x

      y=x+lowbit(x)=x + 2^i

      由于x < z < y,因此z=x+b,其中b的范围是[1, 2^i-1]

      显然lowbit(z) = lowbit(b)

      又由于b >= lowbit(b)

      因此L(z) = z-lowbit(z)+1=x+b-lowbit(b)+1>=x+1>x

    (3)设1<=x<=y<=z,若y覆盖x,z覆盖y,那么z覆盖x

      可证[L(y),y]属于[L(z),z],那么因为x属于[L(y),y],z覆盖x得证。

      z可以表示为a*2^(i+1)+2^i, 其中lowbit(z) = 2^i,L(z) = a*2^(i+1)+1

      因为z覆盖y,则y>=L(z)=a*2^(i+1)+1, 并且y<=z = a*2^(i+1)+2^i,

      所以y可以表示为y=a*2^(i+1)+b ,其中b的取值范围是[1,2^i];

      所以lowbit(y) = lowbit(b)

      并且显然有b-lowbit(b)>= 0

      因此可得L(y)=y-lowbit(y)+1=a*2^(i+1)+b-lowbit(b)+1

      >=a*2^(i+1)+1=L(z)

      即L(y)>=L(z)

      又由于y<=z

      因此区间[L(y]),y] 属于区间[L(z),z]

      又由于x属于[L(y),y],因此x也属于区间[L(z),z],即z覆盖x;

      证明完毕。

    (4)对于任意正整数x,覆盖x的所有整数有且仅有x,x+lowbit(x),x+lowbit(x)+lowbit(x+lowbit(x)),...

      这一序列用p来表示,即p(0),p(1),p(2),p(3),...

      其中p(0) = x,当i>0时,p(i) = p(i-1)+lowbit(p(i-1))

      命题可以拆开为2部分,第一部分是p序列中任意数都覆盖x,第二部分是任意不在p序列的数字都不覆盖x,接下来分别对两部分进行证明。

      第一部分,p序列中任意数都覆盖x;

      使用数学归纳法证明,

      当i=0时,p(0)=x,显然p(0)覆盖x;

      假设i=k时,p(k)覆盖x;

      当i=k+1时,由p序列定义可知p(k+1)=p(k)+lowbit(p(k)),由反向覆盖性质可知,p(k+1)覆盖p(k),另外p(k)覆盖x,由覆盖的传递性质可知,p(k+1)也覆盖x;

      第二部分是,任意不在p序列的整数都不覆盖x;

      也就是区间序列[1,p(0)),(p(0),p(1)),(p(1),p(2)),(p(2),p(3)),…… 中任意正整数都不覆盖x,因此只需要证明任意一个区间中的任意正整数都不覆盖x即可;

      对于区间[1,p(0))的任意整数y,y<p(0),即y<x,显然y不覆盖x;

      设i是序列p中任意下标,接下来证明任意正整数y都不覆盖x,其中y属于区间(p(i),p(i+1));

      由反向覆盖的排他性可知,y不覆盖p(i),并且L(y)>p(i),又由于p(i)>=x,因此L(y)>x,即y也不覆盖x;

      证明完毕。


 

下面简述单点修改和区间查询的具体操作。

  

 

查询1~x的和:

1 int query(int x){
2     int sum=0;
3     for(int i=x;i;i-=lowbit(i)){
4         sum+=tr[i];
5     }
6     return sum;
7 }

修改x点的值:

1 void add(int x,int y){
2     for(int i=x;i<=n;i+=lowbit(i)){
3         tr[i]+=y;
4     }
5 }

lowbit函数:

  假设x=a*2^(i+1)+2^i,lowbit(i)=2^i,根据计算机内整数是以补码存储的特性

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

 例题:https://www.acwing.com/problem/content/1266/

单点查询,区间修改。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N=100010;
 6 int a[N],tr[N];
 7 int n,m;
 8 int lowbit(int x){
 9     return x&-x;
10 }
11 void add(int x,int y){
12     for(int i=x;i<=n;i+=lowbit(i)){
13         tr[i]+=y;
14     }
15 }
16 int query(int x){
17     int sum=0;
18     for(int i=x;i;i-=lowbit(i)){
19         sum+=tr[i];
20     }
21     return sum;
22 }
23 int main()
24 {
25 
26     cin>>n>>m;
27     for(int i=1;i<=n;i++){
28         cin>>a[i];
29         add(i,a[i]);
30     }
31     for(int i=0;i<m;i++){
32         int k,x,y;
33         cin>>k>>x>>y;
34         if(k==0) cout<<query(y)-query(x-1)<<endl;
35         else if(k==1) add(x,y);
36     }
37     return 0;
38 }

若是每次操作是将一个数变为另一个数,则还需要维护a数组,这样的话就方便计算出差值。

另:树状数组本质上是只能完成单点修改区间查询的操作,但是结合一些方法还是能够得到较好的应用的。

  比如结合差分便可实现区间修改,单点查询。

 

标签:单点,覆盖,树状,--,lowbit,int,区间,数据结构,任意
来源: https://www.cnblogs.com/greenofyu/p/14820778.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有