树状数组(Binary Indexed Tree, BIT)

  • 本质上是按照二分对数组进行分组,维护和查询都是O(lgn)的复杂度
  • 树状数组与线段树:树状数组和线段树很像,但能用树状数组解决的问题,基本上都能用线段树解决,而线段树能解决的树状数组不一定能解决。相比较而言,树状数组效率要高很多。

  • lowbit

    • lowbit = x & (-x)
    • lowbit(x)也可以理解为能整除x的最大的2的幂次
  • c[i]存放的是在i号之前(包括i号)lowbit(i)个整数的和(即:c[i]的覆盖长度是lowbit(i) )
  • 树状数组的下标必须从1开始

单点更新,区间查询

int getsum(int x)函数:返回前x个整数之和

int getsum(int x) {int sum = 0;for(int i = x; i >= 1; i -= lowbit(x))sum += c[i];return sum;
}
  • 如果要求[x, y]之内的数的和,可以转换成getsum(y) - getsum(x - 1)来解决

void update(x, v)函数:将第x个数加上一个数v

void update(int x, int v) {for(int i = x; i <= n; i += lowbit(x))c[i] += v;
}

经典应用:统计序列中在元素左边比该元素小的元素个数

#include <cstdio>
#include <cstring>
const int maxn = 10010;
#define lowbit(i) ((i) & (-i))
int c[maxn];
void update(int x, int v) {for(int i = x; i < maxn; i += lowbit(i))c[i] += v;
}
int getsum(int x) {int sum = 0;for(int i = x; i >= 1; i -= lowbit(i))sum += c[i];return sum;
}
int main() {int n, x;scanf("%d", &n);for(int i = 0; i < n; i++) {scanf("%d", &x);update(x, 1);printf("%d\n", getsum(x - 1));}return 0;
}

如果是求序列第k大的问题:

可以用二分法查询第一个满足getsum(i) >= k的i

int findKthElement(int k) {int l = 1, r = maxn; mid;while(l < r) {mid = (l + r) / 2;if(getsum(mid) >= K)r = mid;elsel = mid + 1;}return l;
}

如果给定一个二维整数矩阵A,求A[1][1]~A[x][y]这个子矩阵中所有元素之和,以及给单点A[x][y]加上整数v:

只需把getsum和update函数中的for循环改为两重

int c[maxn][maxn];
void update(int x, int y, int v) {for(int i = x; i < maxn; i += lowbit(i)) {for(int j = y; j < maxn; j += lowbit(j)) {c[i][j] += v;}}
}int getsum(int x, int y) {int sum = 0;for(int i = x; i >= 1; i -= lowbit(i)) {for(int j = y; j >= 1; j -= lowbit(j))sum += c[i][j];}return sum;
}

区间更新,单点查询

  • 将getsum改为沿着i增大lowbit(i)的方向
  • 将update改为沿着i减小的lowbit(i)的方向
  • c[i]不再表示这段区间的元素之和,而是表示这段区间每个数被加了多少
  • int getsum(int x)返回第x个整数的值(就是从小块到大块累加一共被增加了多少)
int getsum(int x) {int sum = 0;for(int i = x; i < maxn; i += lowbit(i))sum += c[i];return sum;
}
  • void update(int x, int v)是将前x个整数都加上v
void update(int x, int v) {for(int i = x; i >= 0; i -= lowbit(i))c[i] += v;
}

  • 所以,~~i从x往后是从小块更新到大块c[i],i从x往前是累加前面的覆盖块的值~

1057. Stack (30)-PAT甲级真题(树状数组)

  • 求栈内所有元素的中位数:用排序查询的方法会超时~~~用树状数组,即求第k = (s.size() + 1) / 2大的数。查询小于等于x的数的个数是否等于k的时候用二分法更快~
#include <cstdio>
#include <stack>
#define lowbit(i) ((i) & (-i))
const int maxn = 100010;
using namespace std;
int c[maxn];
stack<int> s;
void update(int x, int v) {for(int i = x; i < maxn; i += lowbit(i))c[i] += v;
}
int getsum(int x) {int sum = 0;for(int i = x; i >= 1; i -= lowbit(i))sum += c[i];return sum;
}
void PeekMedian() {int left = 1, right = maxn, mid, k = (s.size() + 1) / 2;while(left < right) {mid = (left + right) / 2;if(getsum(mid) >= k)right = mid;elseleft = mid + 1;}printf("%d\n", left);
}
int main() {int n, temp;scanf("%d", &n);char str[15];for(int i = 0; i < n; i++) {scanf("%s", str);if(str[1] == 'u') {scanf("%d", &temp);s.push(temp);update(temp, 1);} else if(str[1] == 'o') {if(!s.empty()) {update(s.top(), -1);printf("%d\n", s.top());s.pop();} else {printf("Invalid\n");}} else {if(!s.empty())PeekMedian();elseprintf("Invalid\n");}}return 0;
}

【数据结构】树状数组笔记相关推荐

  1. js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree)

    本文来源于力扣圈子,作者:胡小旭.点击查看原文 力扣​leetcode-cn.com 树状数组或二叉索引树(英语:Binary Indexed Tree),又以其发明者命名为 Fenwick 树.其初 ...

  2. 数据结构——树状数组

    我们今天来讲一个应用比较广泛的数据结构--树状数组 它可以在O(nlogn)的复杂度下进行单点修改区间查询,下面我会分成三个模块对树状数组进行详细的解说,分别是树状数组基本操作.树状数组区间修改单点查 ...

  3. 数据结构--树状数组

    文章目录 1. 树状数组 2. 单点修改 3. 区间修改 4. 完整代码 5. 参考文献 1. 树状数组 类似数据结构:线段树(Segment Tree) 树状数组 跟 线段树 的区别: 树状数组能做 ...

  4. 2017西安交大ACM小学期数据结构 [树状数组 离散化]

    Problem E 发布时间: 2017年6月28日 12:53   最后更新: 2017年6月29日 21:35   时间限制: 1000ms   内存限制: 64M 描述 给定一个长度为n的序列a ...

  5. 2017西安交大ACM小学期数据结构 [树状数组,极大值]

    Problem D 发布时间: 2017年6月28日 10:51   最后更新: 2017年6月28日 16:38   时间限制: 1000ms   内存限制: 32M 描述 给定一个长度为n的序列a ...

  6. 2017西安交大ACM小学期数据结构 [树状数组]

    Problem C 发布时间: 2017年6月28日 11:38   最后更新: 2017年6月28日 16:38   时间限制: 1000ms   内存限制: 32M 描述 给定一个长度为n的序列a ...

  7. 数据结构 —— 树状数组

    [概述] 树状数组又称二叉索引树,常用于高效计算数列的前缀和.区间和,其查询.修改的时间复杂度为 log(n),空间复杂度为 O(n) 树状数组通过将线性结构转化成树状结构,从而进行跳跃式扫描. 优点 ...

  8. Java数据结构-树状数组

    什么是树状数组?[面试5.0] 使用数组表示多叉树的结构,和优先队列有点类似,区别在于优先队列只表示二叉树 主要用来: 更新数组元素的数值并且求数组前K个元素的总和或平均值 时间复杂度为O(logN) ...

  9. “高级”数据结构——树状数组

    数据结构是每一个程序员都必须要学的,非常重要! 大佬的博客写的真好,虽然我看不懂..... 链接http://www.cnblogs.com/RabbitHu/p/BIT.html

最新文章

  1. startprocessinstancebykey()里面填写的参数_3种方法,快速学会在Word文档里面如何插入表格...
  2. c/c++ 结构体前加不加typedef有什么区别?
  3. java大会主题曲_网易未来大会主题曲发布,从创作到演唱都由AI包办
  4. oracle 的行级触发器
  5. 关于用串口IDLE中断,DMA_GetCurrDataCounter()函数值不变的问题
  6. 联想Z5手机夺得京东销量第一,联想这是要翻盘的节奏吗?
  7. Kubernetes-负载均衡器Load Balancer(十八)
  8. python自动化测试-Python自动化测试入门,看这一篇就足以
  9. 吐血干货,直播首屏耗时400ms以下的优化实践
  10. 如何在计算机管理路由器,怎么查看路由器的管理IP地址?
  11. 一:springCloud服务发现者,服务消费者(方志朋《史上最简单的 SpringCloud 教程》专栏读后感)
  12. VTN系列多通道采集仪硬件接口
  13. Swift中数组字典和plist文件的转换
  14. b java 之 serviceLoader详解 serviceLoader.load(XXX.class)
  15. 一个完整的App应该具备哪些功能
  16. 人工智能阿发狗技术都包含哪些内容
  17. c语言将首字母变大写,c语言问题 将首字母变为大写
  18. vue请求拦截 给所有的api接口的请求 params 带上一个存储的值及qs的安装
  19. Arduino配置WS2812及Adafruit_NeoPixel库的使用
  20. 基于Laya游戏引擎实现微信小游戏排行榜

热门文章

  1. hibernate级联删除问题
  2. vim编辑器的快捷键使用
  3. Java Code Examples for org.apache.ibatis.annotations.Insert
  4. java抓取动态生成的网页
  5. Linux 常用名利总结
  6. 设置c++程序的堆栈空间解决栈溢出问题
  7. HTML5体感游戏《守护拉普达》诞生记
  8. Emacs配置文件(备份用)
  9. 热门Ruby 库中存在严重的命令注入漏洞
  10. Linux OS 曝新漏洞 攻击者可在多数发行版获root 权限