树状数组 学习

 

 

 

 

对于线段树,主要是编程比较麻烦,而树状数组编程比较容易,对于一些问题,使用树状数组会比较方便。

 

 

 

c[i]表示的是区间长度为 2的(i的后连续的0的个数)幂次:2^k(k为最后的连续的0的个数)

 

原数组a[]

 

hint:c数组和a数组都是从下标为1开始的

 

1)对于树状数组某一个区间的

修改操作:

假设需要修改a[k];

首先,我们只要知道哪些c里面记录的包含了a[k]这个元素。如果包括的话,它也需要被修改。由于树状数组的结构定义的特点,我们能知道。


例如:假设a的第di=3个数被修改了,那么包含di的区间的c[i],di的末尾有连续k个0。此时,i=di+2^k。然后依次递推下去,将所有包含了di个元素的c[i]都进行相应的改变。算法如下。

 

// 求x所表示的区间的长度

 

inline int lowbit(int x)

{

    return x&-x ;

}

 

 

void change(int di,int x)

{

while(di<=Maxa)

{

c[di] += x ;

di += lowbit(di);

}

}

 

 

这里其实很不好理解,感觉我每次看树状数组都会重新的理解一下这个change函数的意思。

最好的方法是举例子:如下举2个例

ex1:di=2,首先看图di=2(10),加上2的话,正好是di=4,然后可以知道这里,有点想在将1进行左移位运算。

ex2:di=3,首先看图di=3(11),加上1的话,正好是di=4。这里都正好是它们的祖先节点,不知道这里说祖先节点是否合适。

对于,所有的节点,它的所有的祖先节点记录了孩子节点的信息,所以,当孩子的信息进行了变化时,那么他们的祖先都得进行相应的变化。

 

 

这里其实,我也不是十分的清楚为什么是向上加lowbit(di)得到的区间就是包含当前的区间。让我再想想吧。。。

这里有一点的是,当第一次加上了一个lowbit(di)的时候,di就变成了2的幂次了。

 

树状数组真的很有意思,感觉很是神奇~~

 

2)询问某一个区间的操作:

 

int query(int di)

{

int ret=0;

while(di>0)

{

ret+=c[di];

di-=lowbit(di);

}

return ret;

}

 

这里用di=6作为例子来举例很好。

 

通过计算,可以知道c[di]记录的区间的大小是2。而我们需要知道的是区间大小是6,所以还需要继续计算剩下的6-2个区间。

然后,一直这样循环下去。

 

ex2:

当di=4时,可知,c[di]记录的区间大小正好是4,那么直接就ok了。

 

这里对于query的操作还是很容易懂的。

 

 

一维的树状数组就简单的介绍到这里

 

 

 

///

接下来的是 二维的树状数组:

 

int c[MAXNUM][MAXNUM];

int Lowbit(int m)

{

    return m&(-m);

}

int query2(int i,int j)

{

    int tempj,sum=0;

    while(i>0)

    {

        tempj = j;

        while(tempj>0)

        {

            sum += c[i][tempj];

            tempj -= Lowbit(tempj);

        }

        i -= Lowbit(i);

    }

    return sum;

}

void change2(int i,int j,int m,int MAXNUM)

{

    int tempj;

    while(i<=MAXNUM)

    {

        tempj = j;

        while(tempj<=MAXNUM)

        {

            c[i][tempj] += m;

            tempj += Lowbit(tempj);

        }

        i += Lowbit(i);

    }

}

 

其实二维的也十分的简单,至少思想也很简单,可以这么理解,对于想要知道区间[1,1]到[i,j]的矩形区域里的总和,这时,我们最简单的方法是一个个的累加这个矩形区域里的所有值,此时,一般你会这么进行累加,一行一行的进行。而此时,如果我们假设,我们可以在一行累加的时候不用累加所有的数,而只需要累加一些连续的区域,这里使用树状数组可以。

而在累加所有的行的时候也是如此,我们对 一些连续的行的区域进行累加。

 

感觉讲的好绕啊,自己理解吧,最简单的是自己脑子运行一下query2(2,2),你肯定会懂的,呵呵。

这种方法能很好的实现矩形区域的累和。二维区域。

 

 

 

到这里,就简单的学完了基本的树状数组的相关内容了,剩下的就是去使用了与提高认识了

 

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值