树状数组和线段树的简要描述


最近在看树状数组和线段树,没完整看完,把目前学的暂时记录,后续再补。

线段树和树状数组都是对区间操作的数据结构

 1 #define ls (x<<1)
 2 #define rs (x<<1|1)
 3 using namespace std;
 4 const int N=1e5+5;
 5 int sum[N<<2]//元素a数组的N和树上节点数转换关系是4n-1,所以开4倍算上最后一层空节点,因为其他函数要访问;
 6 int t[N<<2],a[N]; 
 7 void update(int x)
 8 {
 9     sum[x]=sum[ls]+sum[rs]; 
10 }
11 void build(int l,int r,int x)
12 {
13     if(l==r)
14     {
15         t[x]=a[l];//数节点存储的数组元素值;
16         return; 
17     }
18     int mid=l+r>>1;
19     build(l,mid,ls);
20     build(mid+1,r,rs);
21     update(x);//这里的功能暂时是区间求和 
22 }

树状数组核心思想是利用某个数的二进制进行sum求和

如10的二进制1010,有两个1,故可以拆分为2个集合来求1-10的区间和;

记录数组c[n+1], 前10个元素和c[10]   1010是由c[10]+c[8]两个子集和相加获得;

lowbit 是i&(-i)获取二进制第一个1的十进制数,如1010 lowbit后是0010=2;

大概知道怎么求和了,后面就是怎么获取c数组,有c数组我们可以在log的时间内区间求和

C数组获取就是更新树,对于每一个a[i]我们要考虑哪些子集包含a[i],后续的操作会对所有包含a[i]的子集进行更新

基于这样的思想

对于101000这样的数无论101后面是什么01的组合都不能使得101000包含在这些组合里,因为lowbit的最小结果是变成101000而包含元素起点是101001;

所以由枚举思想我们+lowbit发现变成110000 这个集合lowbit后是100001-110000这个区间101000包含在此,不难发现对于

110000,11后的0随便01组合最小值为110001-组合数>101000;

所以lowbit的正确性和唯一性我们都能保证,具体证明别处也有可以去看看,下面上代码;

 1 int c[N],a[N];
 2 inline int lowbit(int i){return i&(-i);}
 3 //不要从0开始lowbit(0)是0下面会T;
 4 void update(int i,int val)
 5 {
 6     for(;i<=N;i+=lowbit(i))c[i]+=val;
 7 }
 8 //初始化就是 
 9 for(int i=1;i<=N;i++)update(i,a[i]); 
10 //先更到这后面在更; 

相关