您的位置:首页 > 其它

树状数组小结(未完待续)

2017-08-04 08:41 183 查看
最近刚刚深入到了树状数组是什么,上年寒假学过,但是当时完全听不到,最近两天沉下心来,好好看了下,终于懂这个原理是什么,感觉并不是很难,而且很好用。


这个图应该更好理解:

d[1]=a[1];

d[2]=a[1]+a[2];

d[3]=a[3];

d[4]=a[1]+a[2]+a[3]+a[4];

依次类推,6管着5和6  8管着前8项,如果一个N (偶数)除以2还是一个偶数那他将是这个N项的和,如果是奇数的那他将管着N-1和第N项这两项的和

比如说对数组a,改变某一位的值需O(1),求某个k区间值O(k);

这样的m次操作是用O(m*k);

显然数据很大时,效率要差很多;

而树状数组,它改变某一位,或者求某个区间的和,都是O(logN);效率大为改善;

对于上图怎么计算区间的和;关键是需要几个函数;

先说树状数组最简单的用法,修改上面图中的某个点,并求某段区间的和;
下面介绍几个函数,用这几个来处理树状数组的问题。

第一个函数;

1 int lowbit(int x)
2 {
3     return x&(-x);
4 }


这个函数主要是用来求的是某个点管辖范围;

x&(-x);  对于& 可
d9b2
以百度下看看讲解,这个在这里就不多说了

如果是x+=x&(-x);就是得到的改点的父节点的值;比如x=4时;就能得到8;

而x-=x&(-x)的话,就是得到x这个点的管辖区间的下个区间的管辖点;

比如说,x=7,x&(-x)等于1,此时x=6不断循环到0能依次得到 6. 4.;

对于一个偶数他整除2还是偶数那么他将是前几项的和 它进行x&(-x)等于他自己的本身,奇数为1,可以自己手动打印几组观察下。

把他们所有的管辖区间正好是1....7;

第二个函数

1 void update(int x,int num)
2 {
3     while(x<=N)
4      {
5          d[x]+=num;
6          x+=lowbit(x);
7      }
8 }


这个函数,是用来修改树状数组的;从当前点开始到它的爸爸,爷爷,这样的长辈都得需要改变。

如果是一般的算法只用修改改点就可;但是树状数组必须修改所有改点被管辖的区间;

比如把a数组的 a[2]减去1,(令N=16);则所有2被管辖的点有4,8,16都应该减去1;

就是调用函数 update(2,-1);

第三个函数

1 int getSum(int x)
2 {
3     int s=0;
4     while(x>0)
5      {
6          s+=d[x];
7          x-=lowbit(x);
8      }
9     return s;
10 }


这个函数就是求区间和了。。比如getSum(7)的话,就是求a[1]+a[2]+...a[7];

上面是最基本的用法;要学习树状数组必须把上面的过程原理搞明白;
它这样求和 比如7  会先加7  然后加6 然后加4  7包括自己 ,6包括5和6,4包括前四项,所以这样就求出来了前七项的和。 

题目大体上可以分为两种(还有其他的就不多介绍了):

一,每次修改的是一个点,所求的是关于某段区间;

二,每次修改的是一个区间,所求的值是关于某个点的;

推荐博客:http://www.cnblogs.com/Penn000/articles/5758324.html

推荐题目:HDu 1556 Color the ball   HDu 2689 sort it    HDu 1166  poj2352 stars

相关题解在树状数组专栏有。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: