从0开始学算法--基础数据结构(2.9树状数组)

时间:2019-10-21
本文章向大家介绍从0开始学算法--基础数据结构(2.9树状数组),主要包括从0开始学算法--基础数据结构(2.9树状数组)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

  给你一个数组a[],求一段连续区间的和;

  解:可以用sum[i]表示a[1]到a[i]的和,这样求a[l]到a[r]的和就变成了求sum[r]-sum[l-1],预处理O(n)的时间复杂度处理出sum[]之后查询只需要O(1)  

  (注释:把l-r的问题转化为1-l,1-r的问题是一种常用思想)

  但是如果加入另外一个操作给a[i]加上x,发现,如果给第一个元素加上x之后全部元素都会加上x,时间复杂度就会很大

  那么应该怎么办?

  修改和查询一个操作是O(1),一个操作是O(n)(这不是数组和链表吗)

  所以可以用分块的思想分成根号n块,每块记录他的前缀和,这样查询和修改都变成了根号n的时间复杂度

  但是这种分配方式并不算好,有没有更好的分配方式呢?

树状数组:

在树状数组中sum[i]代表的是a[i-lowbit(i)]到a[i]的和

lowbit(i)是i在二进制中最后一位1,例如i是二进制数10100,那么lowbit(i)=4(二进制100)

那么可以得到求前n项的和是只有求二进制位为一的项数之和,为1的位数不超过logn所以查询的时间复杂度为logn

同理修改操作也只会影响logn个位置的值,那么修改的操作也是logn的时间复杂度

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

void add(int x,int y){//给a[x]+y
    while(x<=n){
        sum[x]+=y;
        x+=lowbit(x);
    }
}

int qian_zhui_he(int x){//求a[1]到a[x]的和
    int ans=0;
    while(x>0){
        ans+=sum[x];
        x+=lowbit(x);
    }
    return ans;
}

注释:如果a[]初始数组不全为0,那么给每个点做一次add操作即可

原文地址:https://www.cnblogs.com/wz-archer/p/11714535.html