树状数组--二叉索引树

突然发现

自己好久好久没写博客了

大概是最近要做的题太多了吧

而在写这篇之前

我还犹豫了好久

自己思索好大一番为什么要写博

差点放弃的时候

我终于找的一个小小的理由

 

我记性实在是太差了

而翻书,上网查有一点点绕弯路

所以

我坚持了

-------------------------------------------------

不得不说

我的知识点漏洞太大了

一方面是我记性不好

一方面是我太懒了

(一定要改啊啊!!)

蒟蒻的卑微

----------------------------------------------

那么

进入正题

---------------------------------------------

动态连续和查询问题。

给定一个n个元素的数组A1、A2、...,An,我们的任务是设计一个数据结构,支持以下两种操作。

***  add(x,d)操作:让Ax增加d。

***  Query(L,R):计算AL+AL+1+...AR。

为了更快的操作(为了不tle)

用一种称为二叉索引树(BIT)的数据结构

 

****************************************************************************************************************

前置知识:

lowbit

对于一个正整数x,我们定义lowbit(x)为x的二进制表达式中最右边的1所对应的值

eg.38288 的二进制是 1001010110010000 所以lowbit(38288) = 16(16的二进制是10000)

在程序实现中:

    lowbit(x) = x &(-x);

(-x是x按位取反,末尾加1的结果)

 

 38288 = 1001010110010000

-38288 = 0110101001110000

两者按位“与”后,前面的部分全变0,之后(后5位)lowbit保持不变

 

*******************************************************************************************************************

 

灰色结点点是BIT中的结点(白条一会儿再说)

每一层结点的lowbit相同

而且lowbit越大越靠近根

注意:
  编号为0的点是虚拟结点,并不是树的一部分,但是,它的存在会让算法更容易理解。

 

对于结点i:

  若为左子结点:的父结点编号为i + lowbit(i);

  若为右子结点:他的父结点编号为i - lowbit(i);

(应该不用证明,直观感受它的正确性,并记住这个性质就好)

 

构造一个辅助数组C:

  Ci=Ai-lowbit(i)+1 + Ai-lowbit(i)+2+...+Ai

C的每个元素都是A数组中的一段连续和。

在BIT中每个灰色结点i都属于一个以它自身为结尾的水平长条

(lowbit = 1的那些点,“长条”就是那个结点自己)

这个长条中的数之和就是Ci

eg.结点12的长条就是从9~12,即C12=A9+A10+A11+A12

eg.C6=A5+A6

 

 

Query(L,R)-----------求和

顺着结点i往左走,边走边“往上爬”(不一定沿着树中的边爬)

把沿途经过的Ci累加起来就可以啦

(沿途经过的Ci所对应的长条不重复也不遗漏的包含了所有需要累加的元素)

 

int sum(int x)
{
    int ret = 0;
    while(x > 0)
    {
        ret += C[x];
        x -= lowbit(x);
    }
    return ret;
} 

 

 

add(x,d)----------增加

从Ci开始往右走,边走边“往上爬”(同样,不一定沿着树中的边爬)

沿途修改所有结点的Ci即可(有且仅有这些结点对应的长条包含被修改的元素)

void add(int x,int d)
{
    while(x <= n)
    {
        C[x] += d;
        x +=lowbit(x);
    }
}

 

 

两个时间复杂度均为O(nlogn)

posted @ 2019-02-14 18:20  darrrr  阅读(377)  评论(0编辑  收藏  举报