Binary_Indexed_Tree (BIT)

树状数组

树状数组:

是一种设计新颖的数组结构,它能够高效地获取数组中连续n个数的和。

线性结构只能逐个扫描元素,而树状结构可以实现跳跃式扫描。

概括说:

树状数组通常用于解决以下问题:

数组{a}中的元素可能不断地被修改,怎样才能快速地获取连续几个数的和?

一般讲到树状数组都会少不了下面这个图:

下面来解析该图,找出其中的规律:

据图可知:

c1 = a1

c2 = a2

c3 = a3

c4 = a1 + a2 + a3 + a4

c5 = a5

c6 = a5 + a6

c7 = a7

c8 = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8

c9 = a9

分析上面的几组式子可知:

当i为奇数时

  ci = ai

当i为偶数时

  就要看i的因子中最多有2的多少次幂。

For Example:

6的因子中有2的一次幂,等于2。所以 c6 = a5 + a6 (由6向前数两个数的和)。

4的因子中油2的二次幂,等于4。所以 c4 = a1 + a2 + a3 + a4 (由4向前数四个数字的和)。

一、有公式 cn = a (n - a^k +1) + ......+ an (其中k为n的二进制表示中从右往左数的0的个数)。

  那么如何求 a^k 呢?

  求法如下:

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

lowbit () 的返回值就是 2^k 次方的值。

  求出来 2^k 之后,数组 c 的值也就都出来。

  接下来我们要求数组中所有元素的和。

二、求数组的和的算法如下:

  ① 令sum = 0,转向第②步;

  ② 接下来判断,如果 n > 0 的话,就令sum = sum + cn 转向第③步,否则的话,终止算法,返回sum的值;

  ③ n = n - lowbit(n) (将n的二进制表示的最后一个0删掉),返回第二步。

 1 int sum(int n)
 2 {
 3     int sum = 0;
 4     while (n > 0)
 5     {
 6         sum+=c[n];
 7         n = n - lowbit(n);
 8     }
 9     return sum;
10 }

三、当数组中的元素有变更时,树状数组就发挥它的优势了,(修改为给某个节点 i 加上 x)算法如下:

  ① 当 i < n 时,执行下一步;否则的话,算法结束;

  ② ci = ci + x, i = i + lowbit (i) (在 i 的二进制表示的最后加0);返回第 ① 步。

1 void change(int i, int x)
2 {
3     while(i <= n)
4     {
5         c[i] = c[i] + x;
6         i = i + lowbit(i);
7     }
8 }

时间: 2024-10-05 04:40:53

Binary_Indexed_Tree (BIT)的相关文章

树形数组 学习之外总能发现别人更好的

 <html> <HEAD></HEAD> <BODY> <textarea rows="50" cols="50">  /***************** http://www.anycodes.cn/zh/  [[树状数组]线段数]  高效:log(n)  操作:位操作  思想:二分法  百度百科之外还有以下博客 http://dongxicheng.org/structure/binary_inde

Gym 100960G (set+树状数组)

Problem Youngling Tournament 题目大意 给一个序列a[i],每次操作可以更改一个数,每次询问 将序列排序后有多少个数a[i]>=sum[i-1]. n<=10^5,q<=5*10^4,a[i]<=10^12 解题分析 可以发现,在最优情况下,该序列长度最多为logn. 将询问离线后,用multiset来维护a[i],用树状数组来维护sum[i].树状数组所存下标为离散化后的a[i]. 每次查询时跳跃式地在set中查找. 时间复杂度 O((n+m)log(

HDU 5862(离散化+树状数组)

Problem Counting Intersections 题目大意 给定n条水平或竖直的线段,统计所有线段的交点个数. (n<=100000) 解题分析 首先将线段离散化. 然后将所有线段按照横坐标的顺序,按照先插入再查找再删除的顺序进行操作. 对于横线 如果是左端点,则将其纵坐标加1,右端点则减1,对于竖线直接求和就行了. 参考程序 1 #include <map> 2 #include <set> 3 #include <stack> 4 #include

雅礼学习10.6

雅礼学习10.6 上午考试 各题状况 T1 二分答案 应该有反例,就是说,答案应该不是单调的 但是不会写其他的算法了啊... T2 我TM... 第二个红框圈出来的部分应该是 if(x1+x1!=s) 写错了,就没了\(18\)分.. T3 写了个\(n^4\)的暴力 最后发现题目中的矩形的四个顶点不一定是给定的顶点.. 那就GG了 各题题目及考场代码 T1 /* * 二分答案.. * 复杂度O(20(N+NlogN+M))的,感觉很悬 * 排序应该可以优化掉,但是不太会哎. */ #inclu

[HEOI 2012] 采花

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2743 [算法] 首先预处理nxt[]数组 , 其中 , nxt[i]表示下一个和i号位颜色相同的位置 , 然后离线 , 将询问按左端点排序 , 每次将nxt[i]减一 , nxt[nxt[i]]加一 用树状数组维护即可 , 详见代码 时间复杂度 : O(MlogN) [代码] #include<bits/stdc++.h> using namespace std; const i

[Usaco2015DEC] Breed Counting

[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4397 [算法] 树状数组 时间复杂度 : O(QlogN) [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 100010 int n , q; struct Binary_Indexed_Tree { int c[MAXN]; inline int lowbit(int x) { return x &a

[bzoj4889] [Tjoi2017]不勤劳的图书管理员

Description 加里敦大学有个帝国图书馆,小豆是图书馆阅览室的一个书籍管理员.他的任务是把书排成有序的,所以无序的书让他产生厌烦,两本乱序的书会让小豆产生这两本书页数的和的厌烦度.现在有n本被打乱顺序的书,在接下来m天中每天都会因为读者的阅览导致书籍顺序改变位置.因为小豆被要求在接下来的m天中至少要整理一次图书.小豆想知道,如果他前i天不去整理,第i天他的厌烦度是多少,这样他好选择厌烦度最小的那天去整理. Input 第一行会有两个数,n,m分别表示有n本书,m天 接下来n行,每行两个数