1.“树状数组”数据结构的一种应用

  对含有n个元素的数组(a[1],...,a[k],...,a[n]):

  (1)求出第i个到第j个元素的和,sum=a[i]+...+a[j]。

    进行j-i+1次加法,复杂度为O(j-i+1)

  (2)任意修改其中某个元素的值。

    使用数组下标可以直接定位修改,时间复杂度为O(1)

  对于同时支持上述两种操作的系统中,求和操作(1)求任意连续个数组元素和的平均时间复杂度为O(n),修改操作(2)时间复杂度是O(1)。如果系统中大量进行上述两种操作m次,其中执行操作(1)概率1/p,操作(2)概率1-1/p,则系统时间复杂度为:

  可以使用树状数组使得上述两种操作的时间复杂度为O(m*logn)

2.树状数组介绍

  核心思想:

    (1)树状数组中的每个元素是原数组中一个或者多个连续元素的和。

    (2)在进行连续求和操作a[1]+...+a[n]时,只需要将树状数组中某几个元素的和即可。时间复杂度为O(lgn)

    (3)在进行修改某个元素a[i]时,只需要修改树状数组中某几个元素的和即可。时间复杂度为O(lgn)

  下图就是一个树状数组的示意图:

  解释如下:

  1) a[]: 保存原始数据的数组。(操作(1)求其中连续多个数的和,操作(2)任意修改其中一个元素)

    e[]: 树状数组,其中的任意一个元素e[i]可能是一个或者多个a数组中元素的和。如e[2]=a[1]+a[2]; e[3]=a[3]; e[4]=a[1]+a[2]+a[3]+a[4]。

  2) e[i]是几个a数组中的元素的和?

    如果数字 i 的二进制表示中末尾有k个连续的0,则e[i]是a数组中2^k个元素的和,则e[i]=a[i-2^k+1]+a[i-2^k+2]+...+a[i-1]+a[i]。

    如:4=100(2)  e[4]=a[1]+a[2]+a[3]+a[4];

      6=110(2)  e[6]=a[5]+a[6]

      7=111(2)  e[7]=a[7]

  3) 后继:可以理解为节点的父亲节点。是离它最近的,且编号末位连续0比它多的就是的父亲,如e[2]是e[1]的后继;e[4]是e[2]的后继。

      如e[4] = e[2]+e[3]+a[4] = a[1]+a[2]+a[3]+a[4] ,e[2]、e[3]的后继就是e[4]。

      后继主要是用来计算e数组,将当前已经计算出的e[i]添加到他们后继中。

    前驱:节点前驱的编号即为比自己小的,最近的,最末连续0比自己多的节点。如e[7]的前驱是e[6],e[6]的前驱是e[4]。

       前驱主要是在计算连续和时,避免重复添加元素。

      如:Sum(7)=a[1]+...+a[7]=e[7]+e[6]+e[4]。(e[7]的前驱是e[6], e[6]的前驱是e[4])

    计算前驱与后继:

      lowbit(i) = ( (i-1) ^ i) & i ;

      节点e[i]的前驱为 e[ i - lowbit(i) ];

      节点e[i]的前驱为 e[ i + lowbit(i) ]

3.树状数组代码示例

 #include <iostream>
#include <stdio.h> using namespace std; int input(int*,int*,int); ///输入数据
int calStageSum(int*,int); ///计算树状数组
int getSum(int*,int); ///求出前n个数字的和
int updataElement(int*,int*,int,int,int); ///更新某一位置上的元素 int main (){
int n;
int newValue;
cout<<"Input the n(n>3) :";
cin>>n; int *num = new int[n+];
int *sum = new int[n+]; cout<<"Input "<<n<<" numbers"<<endl;
input(num,sum,n);
calStageSum(sum,n); cout<<"The sum of first three number:"<<getSum(sum,)<<endl; cout<<"Update the 2nd number value:";
cin>>newValue;
updataElement(sum,num,n,,newValue); cout<<"The sum of first three number:"<<getSum(sum,)<<endl; delete []num;
delete []sum;
return ;
} int input(int* num,int *sum,int n){
for(int i=;i<=n;i++){
cin>>num[i];
sum[i] = num[i];
}
return ;
} int calStageSum(int *sum,int n){
int lowbit;
int par;
for(int i=;i<=n;i++){
lowbit = ((i-)^i)&i;
par = lowbit+i; ///后继节点id
if(par <= n){
sum[par] = sum[par] + sum[i];
}
}
return ;
} int getSum(int* sum,int n){
int sumPreN = ;
int lowbit = ;
while(n!=){
sumPreN += sum[n];
lowbit = ((n-)^n)&n;
n = n - lowbit; ///前驱节点id
}
return sumPreN;
} int updataElement(int* sum,int *num,int n,int pos,int newvalue){
int lowbit = ;
int dis = newvalue - num[pos];
num[pos] = newvalue;
sum[pos] = sum[pos]+dis; while(true){
lowbit = ((pos-)^pos)&pos;
pos = pos + lowbit; ///后继节点id
if(pos <= n){
sum[pos] = sum[pos]+dis;
}
else
break;
}
return ;
}

树状数组(Binary Indexed Tree) 总结的更多相关文章

  1. 树状数组 Binary Indexed Tree/Fenwick Tree

    2018-03-25 17:29:29 树状数组是一个比较小众的数据结构,主要应用领域是快速的对mutable array进行区间求和. 对于一般的一维情况下的区间和问题,一般有以下两种解法: 1)D ...

  2. 树状数组(Binary Indexed Tree(BIT))

    先不说别的,这个博客为我学习树状数组提供了很大帮助,奉上传送门 http://blog.csdn.net/int64ago/article/details/7429868 然后就说几个常用的操作 in ...

  3. 树状数组(Binary Index Tree)

    一维BIT(单点更新,区间求和): Problem - 1166 #include <iostream> #include <algorithm> #include <c ...

  4. 树状数组,Fenwick Tree

    Fenwick Tree, (also known as Binary Indexed Tree,二叉索引树), is a high-performance data structure to cal ...

  5. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  6. HDU 3436--Queue-jumpers (树状数组 or Splay Tree)

    树状数组这个真心想了好久,还是没想出来 %%% www.cppblog.com/Yuan/archive/2010/08/18/123871.html 树状数组求前缀和大于等于k的最大值,第一次看到这 ...

  7. 树状数组(fenwick tree)

    树状数组又称芬威克树,概念上是树状,实际上是使用数组实现的,表现为一种隐式数据结构,balabala...详情请见:https://en.wikipedia.org/wiki/Fenwick_tree ...

  8. NYOJ 108 士兵杀敌1(树状数组)

    首先,要先讲讲树状数组: 树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之 ...

  9. 树状数组-HDU1541-Stars一维树状数组 POJ1195-Mobile phones-二维树状数组

    树状数组,学长很早之前讲过,最近才重视起来,enmmmm... 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据 ...

随机推荐

  1. Eclipse中syso 快捷键 Alt + / 不能使用的问题

    通过使用windows-preferences-java-editor-templates中的快捷键,可以显著提升输入速度.快捷键的设置一般是在这里以及general下面的keys里面设置. 但是,在 ...

  2. Mac下思维导图Xmind使用入门

    1.软件下载 中文官网地址: http://www.xmindchina.net   安装过程比较傻瓜化,这里就不截图了. 2.用Xmind设计软件模块: 1>.新建一个思维导图,如下图,选 ...

  3. PHP的单引号和双引号

    单引号内部的变量不会执行,双引号会执行. <?php $name = 'hello php'; echo "<h1>$name</h1>"; echo ...

  4. Json格式String类型字符串转为Map工具类

    package agriculture_implement.util; import com.google.gson.Gson; import com.google.gson.JsonSyntaxEx ...

  5. Android ContentObserver详解

    前言: 工作中,需要开启一个线程大量的查询某个数据库值发送了变化,导致的开销很大,后来在老大的指点下,利用了ContentObserver完美的解决了该问题,感到很兴奋,做完之后自己也对Content ...

  6. Android中利用ant进行多渠道循环批量打包

    公司负责Android开发的小伙伴学习能力稍微偏弱,交代给他的自动化打包的任务,弄了好久依然没有成效.无奈只好亲自出手. 没有想到过程很顺利,我完全按照如下文章的步骤进行: 主要参考: Android ...

  7. bzoj1477 poj1061 青蛙的约会

    Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事 ...

  8. C#高级编程9-第2章 核心C#

    C#基础 使用C#命名编译器csc.exe,编译C#程序 变量 变量一般初始化后才能使用 类型判断弱类型var,根据初始值判断类型, 变量作用域,可以访问该代码的区域 类中定义的成员变量和属性,作用在 ...

  9. service redis does not support chkconfig 的解决办法

    问题解决办法如下: 必须把下面两行注释放在/etc/init.d/redis文件靠前的注释中(加入以下注释): # chkconfig: # description: Redis is a persi ...

  10. HDU 4726 Kia's Calculation(贪心)

    Kia's Calculation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...