二叉索引树BIT
定义
二叉索引树,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的更多相关文章
- 【转载】区间信息的维护与查询(一)——二叉索引树(Fenwick树、树状数组)
在网上找到一篇非常不错的树状数组的博客,拿来转载,原文地址. 树状数组 最新看了一下区间的查询与修改的知识,最主要看到的是树状数组(BIT),以前感觉好高大上的东西,其实也不过就这么简单而已. 我们有 ...
- C++实用数据结构:二叉索引树
看下面这个问题(动态连续和查询): 有一个数组A(长度为n),要求进行两种操作: add(i,x):让Ai增大x: query(a,b):询问Aa+Aa+1+...+Ab的和: 若进行模拟,则每次qu ...
- POJ 3321 Apple Tree dfs+二叉索引树
题目:http://poj.org/problem?id=3321 动态更新某个元素,并且求和,显然是二叉索引树,但是节点的标号不连续,二叉索引树必须是连续的,所以需要转化成连续的,多叉树的形状已经建 ...
- NYOJ 116 士兵杀敌(二)(二叉索引树)
http://acm.nyist.net/JudgeOnline/problem.php?pid=116 题意: 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的 ...
- HDU 1166 敌兵布阵(线段树 or 二叉索引树)
http://acm.hdu.edu.cn/showproblem.php?pid=1166 题意:第一行一个整数T,表示有T组数据. 每组数据第一行一个正整数N(N<=50000),表示敌人有 ...
- 【树状数组(二叉索引树)】轻院热身—candy、NYOJ-116士兵杀敌(二)
[概念] 转载连接:树状数组 讲的挺好. 这两题非常的相似,查询区间的累加和.更新结点.Add(x,d) 与 Query(L,R) 的操作 [题目链接:candy] 唉,也是现在才发现这题用了这个知识 ...
- 树状数组(二叉索引树 BIT Fenwick树) *【一维基础模板】(查询区间和+修改更新)
刘汝佳:<训练指南>Page(194) #include <stdio.h> #include <string.h> #include <stdlib.h&g ...
- 二叉索引树,LA2191,LA5902,LA4329
利用了二进制,二分的思想的一个很巧妙的数据结构,一个lowbit(x):二进制表示下的最右边的一个1开始对应的数值. 那么如果一个节点的为x左孩子,父亲节点就是 x + lowbit(x),如果是右孩 ...
- 1.红黑树和自平衡二叉(查找)树区别 2.红黑树与B树的区别
1.红黑树和自平衡二叉(查找)树区别 1.红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单. 2.平衡 ...
随机推荐
- MSSQL复习
1.用户角色: 登录名就相当于一个用户 角色相当于把你的操作权限分组了 2.数据系统结构(略) 网络连接接口 关系引擎 存储引擎 内存 3.数据库的结构 数据库 架构 对象(在Sql server中将 ...
- Firefox渗透测试黑客插件集
前天看S哥用Firefox的hackbar进行手动注入进行渗透,觉得直接运用浏览器的插件进行渗透测试有很多优点,既可以直接在前端进行注入等操作,也可以省却了寻找各种工具的麻烦.前端还是最直接的!于是这 ...
- java对象与json对象间的相互转换
工程中所需的jar包,因为在网上不太好找,所以我将它放到我的网盘里了,如有需要随便下载. 点击下载 1.简单的解析json字符串 首先将json字符串转换为json对象,然后再解析json对象,过程如 ...
- Python获取目录、文件的注意事项
Python获取指定路径下的子目录和文件有两种方法: os.listdir(dir)和os.walk(dir),前者列出dir目录下的所有直接子目录和文件的名称(均不包含完整路径),如 >> ...
- 利用cocostudio库函数 实现左右滑动的背包栏UI (cocos2d-x 2.2.0)
.h #ifndef __COMMON_COMPONENTS__ #define __COMMON_COMPONENTS__ #include "cocos2d.h" #inclu ...
- msysgit ls 中文显示
2013年10月17日 14:54:15 安装了新版的msysgit后,在其自带的 git bash 命令行下就可以输入中文汉字了 但是创建了中文名字命名的文件后,再用 ls 命令查询时会出现乱码的情 ...
- Java面向对象的封装
封装是Java面向对象的三大特性之一,通常我们是通过包管理机制同时对类进行封装,隐藏其内部实现细节,通常开发中不允许直接操作类中的成员属性,所以属性一般设置为私有权限private,类中一般会给出一些 ...
- Linux系统排查2——CPU负载篇
本随笔介绍CPU负载的排查手段. 查看系统负载的工具:uptime,w,都能查看系统负载,系统平均负载是处于运行或不可打扰状态的进程的平均数, 可运行:运行态,占用CPU,或就绪态,等待CPU调度. ...
- Ubuntu及Windows ADB设备no permissions的解决方案
不少人曾在Windows下及Ubuntu下都遇到过Android设备无法识别的情况,就是run as Android Application的时候,target显示"??????" ...
- URAL 1654 Cipher Message 解题报告
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1654 题意:简单的理解就是,把一个序列中相邻的且是偶数个相同的字符删除,奇数个的话就只保 ...
