定义

    二叉索引树,binary index tree,又名树状数组,或Fenwick Tree,因为本算法由Fenwick创造。

    对于数组A,定义Query(i,j) = Ai +Ai+1 + … + Aj.

    比较好的做法:使用前缀和,Sum(j) – Sum(i-1)即可得到Query(i,j)

    BIT即为解决此类区间查询而大展身手,因为预处理时间为O(n),之后的查询时间为O(1),是属于典型的在线算法(关于在线算法,通俗地可以理解为,做一次预处理,提供多次“服务”——比如多次Query(i,j))。

Lowbit(nature)

    首先,定位lowbit(natural)为自然数(即1,2,3…n)的二进制形式中最右边出现1的值。

    比如:4 = 100,lowbit(4) = 4;36 = 100100,lowbit(36) = 4.

    自然数在二进制形式下,有如下的性质:

    Lowbit为1的自然数为1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31…d = 2

    Lowbit为2的自然数为2,6,10,14,18,22,26,30,… d = 4

    Lowbit为3的自然数为4,12,20,28… d=8

    Lowbit为4的自然数为8,32

    直接上刘汝佳的算法竞赛入门竞赛经典中的图片:

    

    树状性质:对于节点i,如果他是左子结点,那么父节点的编号就是i+lowbit(i);如果它是右子节点,那么父节点的编号是i-lowbit(i)。

    令数组C为:

     Ci = Ai-lowbit(i)+1+A i-lowbit(i)+2+…Ai

    即从最左边的孩子,到自身的和,如C12 = A9(上图中最左边的儿子)+A10+A11+A12,C6=A5+A6。

    计算前缀和Sum(i)的计算:

    顺着节点i往左走,边走边“往上爬”,把经过的Ci 累加起来即可。

API

    l lowbit(idx)

      求A[idx]的低位

    l Sum(i)

     求区间1,i的前缀和

    l Add(idx,value)

      使节点idx的值增加value;

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Algorithms.Data_Structure
{
/// <summary>
/// 二叉索引树(树状数组:Fenwick Tree)
/// </summary>
public class BinaryIndexedTree
{
/// <summary>
/// 处理的数组
/// </summary>
private List<int> array; /// <summary>
/// 二叉前缀和
/// </summary>
private List<int> tree; /// <summary>
/// 个数
/// </summary>
private int n; public BinaryIndexedTree(int[] array)
{
this.array = new List<int>(array);
this.n = this.array.Count; PreProcessing();
} /// <summary>
/// 预处理函数:每次增加数值
/// </summary>
private void PreProcessing()
{
tree = new List<int>(n);
for (int ii = 0; ii < n; ii++)
{
tree.Add(0);
} for (int ii = 1; ii < n; ii++)
{
Update(ii, array[ii]);
}
} /// <summary>
/// 二进制形式中的最右边的1所对应的值,如38288 = 1001010110010000 ,则返回16
/// </summary>
/// <param name="idx"></param>
private int lowbit(int idx)
{
return idx & (-idx);
} /// <summary>
/// 在x处加v
/// </summary>
/// <param name="idx">数组的索引,从1开始计数</param>
/// <param name="v">值</param>
public void Update(int idx, int v)
{
while (idx < n)
{
tree[idx] += v;
idx += lowbit(idx); //left's parent
}
} /// <summary>
/// 从0到x求和
/// </summary>
/// <param name="idx">索引,从1开始计数</param>
/// <returns>求和结果</returns>
public int Sum(int idx)
{
int ret = 0;
while (idx > 0)
{
ret += tree[idx];
idx -= lowbit(idx); // right's parent
}
return ret;
}
}
}

Test:

class Program
{
static void Main(string[] args)
{
BinaryIndexedTree bit = new BinaryIndexedTree(new int[] { 0, 1, 2, 3, 4, 5 }); //从1开始计数
Console.WriteLine(bit.Sum(5));//15
bit.Update(4, 23);
Console.WriteLine(bit.Sum(5));//38
}
}

二叉索引树BIT的更多相关文章

  1. 【转载】区间信息的维护与查询(一)——二叉索引树(Fenwick树、树状数组)

    在网上找到一篇非常不错的树状数组的博客,拿来转载,原文地址. 树状数组 最新看了一下区间的查询与修改的知识,最主要看到的是树状数组(BIT),以前感觉好高大上的东西,其实也不过就这么简单而已. 我们有 ...

  2. C++实用数据结构:二叉索引树

    看下面这个问题(动态连续和查询): 有一个数组A(长度为n),要求进行两种操作: add(i,x):让Ai增大x: query(a,b):询问Aa+Aa+1+...+Ab的和: 若进行模拟,则每次qu ...

  3. POJ 3321 Apple Tree dfs+二叉索引树

    题目:http://poj.org/problem?id=3321 动态更新某个元素,并且求和,显然是二叉索引树,但是节点的标号不连续,二叉索引树必须是连续的,所以需要转化成连续的,多叉树的形状已经建 ...

  4. NYOJ 116 士兵杀敌(二)(二叉索引树)

    http://acm.nyist.net/JudgeOnline/problem.php?pid=116 题意: 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的 ...

  5. HDU 1166 敌兵布阵(线段树 or 二叉索引树)

    http://acm.hdu.edu.cn/showproblem.php?pid=1166 题意:第一行一个整数T,表示有T组数据. 每组数据第一行一个正整数N(N<=50000),表示敌人有 ...

  6. 【树状数组(二叉索引树)】轻院热身—candy、NYOJ-116士兵杀敌(二)

    [概念] 转载连接:树状数组 讲的挺好. 这两题非常的相似,查询区间的累加和.更新结点.Add(x,d) 与 Query(L,R) 的操作 [题目链接:candy] 唉,也是现在才发现这题用了这个知识 ...

  7. 树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)

    刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h&g ...

  8. 二叉索引树,LA2191,LA5902,LA4329

    利用了二进制,二分的思想的一个很巧妙的数据结构,一个lowbit(x):二进制表示下的最右边的一个1开始对应的数值. 那么如果一个节点的为x左孩子,父亲节点就是 x + lowbit(x),如果是右孩 ...

  9. 1.红黑树和自平衡二叉(查找)树区别 2.红黑树与B树的区别

    1.红黑树和自平衡二叉(查找)树区别 1.红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单. 2.平衡 ...

随机推荐

  1. 在生产环境使用Docker部署应用

    导读 Docker现在越来越流行,但是真正在生产环境部署Docker还是个比较新的概念,还没有一个标准的流程.作者是ROR的程序员,作者结合平时的部署经验,联系Docker的特点,向大家分享了其在生产 ...

  2. Coursera台大机器学习课程笔记9 -- Logistic Regression

    如果只想得到某种概率,而不是简单的分类,那么该如何做呢?在误差衡量问题上,如何选取误差函数这段很有意思. 接下来是如何最小化Ein,由于Ein是可凸优化的,所以采用的是梯度下降法:只要达到谷底,就找到 ...

  3. 连接池 druid(阿里巴巴的框架)

      引用自:http://blog.163.com/hongwei_benbear/blog/static/1183952912013518405588/ 说的是现在最好的连接池   注: 属性跟 d ...

  4. [ruby on rails] 跟我学之(6)显示指定数据

    根据<[ruby on rails] 跟我学之路由映射>,我们知道,可以访问 GET    /posts/:id(.:format) 来显示具体的对象. 1. 修改action 修改 ap ...

  5. Kruskal vs Borůvka

    做了个对比.Borůvka算法对于稠密图效果特别好.这两个都是求生成森林的算法.Prim+heap+tarjan过于难写不写了. V=200,E=1000 Kruskal method 4875048 ...

  6. ASP.NET 画图与图像处理-如何直接输出到页面

    有时候我们生成的图片并不需要保存到磁盘中,而是直接输出到页面,比如验证码.实时报表等,如何做呢?请参考如下:     protected void Page_Load(object sender, E ...

  7. IIS安装时,添加/编辑应用程序扩展名映射 确定按钮不可用。

    原因是:执行文件的路径太长,需要激活按钮. 方法一:选择较短路径的执行文件,先激活按钮. 方法二:点击该路径,就可以激活确认按钮了.

  8. html标签属性大全

    <marquee>...</marquee>普通卷动 <marquee behavior=slide>...</marquee>滑动 <marqu ...

  9. Java for LeetCode 164 Maximum Gap

    Given an unsorted array, find the maximum difference between the successive elements in its sorted f ...

  10. Java for LeetCode 160 Intersection of Two Linked Lists

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...