树状数组入门笔记

网上有很多关于树状数组的博客,有很多也讲得很好。
但我感觉对于树状数组,自己始终只能去套模板,所以打算自己写一篇博客,梳理梳理树状数组的用法。

首先上一篇博客。树状数组入门
感觉很无敌,入门足够用了。
我们用C[] 数组来储存树状数组中的信息。
这里写图片描述
1=(001) C[1]=A[1];
2=(010) C[2]=A[1]+A[2];
3=(011) C[3]=A[3];
4=(100) C[4]=A[1]+A[2]+A[3]+A[4];
5=(101) C[5]=A[5];
6=(110) C[6]=A[5]+A[6];
7=(111) C[7]=A[7];
8=(1000) C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
找规律发现,C[i]所代表的元素是原数组中以i结尾的,连续的,2^k 个元素。(这里的k其实可以代表这个元素在树中的高度)
所以可以轻松发现这其中有前缀和的性质。
例如前3(11)个元素 就是C[3(11)]+C[2(10)]
再例如前6(110)个元素 就是C[110]+C[100]
每次去除一个末尾1 直至下标为0。
那么 利用前缀和的思想,我们就可以很轻松的求出任意连续区间内的数字的和。
再然后就是修改操作。 每修改一个元素,我们都要修改与之相关的所有元素。
由于树的最高高度为logn层,每层只修改一个元素,所以最多修改logn个元素,因此修改操作的复杂度为O(logn)而普通的前缀和修改一个元素需要O(n)的时间。
同理,对于查询操作,其复杂度也为O(logn).
树状数组模板如下

int lowbit(int x){return x&(-x);}
void add(int i,int val)
{
    for(;i<=n;i+=lowbit(i))
        bit[i]+=val;
}
int query(int i)
{
    int ans=0;
    for(;i>=1;i-=lowbit(i))
        ans+=bit[i];
    return ans;
}

然后树状数组很容易推广到二维,相当于n个树状树状数组加起来。

const int MAX=2555;
int seed=6666;
int n,m,q;
int lowbit(int x)
{
    return x&(-x);
}
int c[MAX][MAX];
int sum(int i,int j)
{
    int tempj,sums=0;
    while(i>0)
    {
        tempj=j;
        while(tempj>0)
        {
            sums+=c[i][tempj];
            tempj-=lowbit(tempj);
        }
        i-=lowbit(i);
    }
    return sums;
}
void update(int x,int y,long long num)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        for(int j=y;j<=m;j+=lowbit(j))
        {
            c[i][j]+=num;
        }
    }
}

未完待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值