【数据结构】—— 树状数组
树状数组
一个正整数 x 的二进制表示为 ,其中等于1的位是
则 x 可以被二进制表示为
不妨设 ,进一步的,区间[1, x] 可以分成 O(logx) 个小区间
这些小区间的共同特点是:若区间结尾为R,则区间长度就是等于R的“二进制分解”下最小的2的次幂,即 lowbit(R).
例如:,区间 [1, 7] 可以分成 [1, 4] [5, 6] [7, 7]
长度分别是 lowbit(4) = 4, lowbit(6) = 2, lowbit(7) = 1
〔manim | 算法 | 数据结构〕 完全理解并深入应用树状数组 | 支持多种动态维护区间操作_哔哩哔哩_bilibili
树状数组(Binary Indexed Tree)是一种 基于上述思想的数据结构,其基本用途就是维护序列的前缀和。对于给定的序列 a ,我们建立一个数组 c, 其中 c[x] 保存 a 的区间
[x - lowbit(x) + 1, x] 中所有数的和,
黑色数组代表原来的数组(下面用A[i]代替),红色结构代表我们的树状数组(下面用C[i]代替),发现没有,每个位置只有一个方框,令每个位置存的就是子节点的值的和,则有
- C[1] = A[1];
- C[2] = A[1] + A[2];
- C[3] = A[3];
- C[4] = A[1] + A[2] + A[3] + A[4];
- C[5] = A[5];
- C[6] = A[5] + A[6];
- C[7] = A[7];
- C[8] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8];
可以发现,这颗树是有规律的
C[i] = A[i - 2k+1] + A[i - 2k+2] + ... + A[i]; //k为i的二进制中从最低位到高位连续零的长度
例如i = 8(1000)时候,k = 3,可自行验证。
这个怎么实现求和呢,比如我们要找前7项和,那么应该是SUM = C[7] + C[6] + C[4];
而根据上面的式子,容易得出
其实树状数组就是一个二进制上面的应用。
树状数组(BIT)—— 一篇就够了 - Last_Whisper - 博客园
树状数组详解 - Xenny - 博客园
AcWing 241. 楼兰图腾
输入样例:
5 1 5 3 2 4
输出样例:
3 4
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 200010;typedef long long LL;int n;
int a[N];
int tr[N];
int greaterr[N], lower[N];//返回非负整数x在二进制表示下最低位1及其后面的0构成的数值
int lowbit(int x)
{return x & -x;
}//将序列中第x个数加上k。
void add(int x, int c)
{for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}//查询序列前x个数的和
int sum(int x)
{int res = 0;for(int i = x; i; i -= lowbit(i)) res += tr[i];return res;
}int main()
{cin >> n;for(int i = 1; i <= n; i ++ ) scanf("%d",&a[i]);//从左向右,依次统计每个位置左边比第i个数y小的数的个数、以及大的数的个数for(int i = 1; i <= n; i ++ ){int y = a[i];//在前面已加入树状数组的所有数中统计在区间[1, y - 1]的数字的出现次数greaterr[i] = sum(n) - sum(y);//在前面已加入树状数组的所有数中统计在区间[y + 1, n]的数字的出现次数lower[i] = sum(y - 1);//将y加入树状数组,即数字y出现1次add(y,1);}//清空树状数组,从右往左统计每个位置右边比第i个数y小的数的个数、以及大的数的个数memset(tr, 0, sizeof tr);LL res1 = 0, res2 = 0;for(int i = n; i; i --){int y = a[i];res1 += greaterr[i] * (LL)(sum(n) - sum(y));res2 += lower[i] * (LL)(sum(y - 1));//将y加入树状数组,即数字y出现1次add(y,1);}cout << res1 << " " << res2;return 0;
}
AcWing 242. 一个简单的整数问题
输入样例:
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 Q 1 Q 2 C 1 6 3 Q 2
输出样例:
4 1 2 5
树状数组 + 差分
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream>using namespace std; typedef long long LL;const int N = 100010;int n, m; int a[N]; LL tr[N];int lowbit(int x) {return x & -x; }void add(int x, int t) {for(int i = x; i <= n; i += lowbit(i)) tr[i] += t; }LL sum(int x) {LL res = 0;for(int i = x; i; i -= lowbit(i)) res += tr[i];return res; }int main() {cin >> n >> m;for(int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);for(int i = 1; i <= n; i ++ ) add(i, a[i] - a[i - 1]);while(m -- ){char op[2];int l, r, d;scanf("%s%d", op, &l);if(*op == 'C'){scanf("%d%d", &r, &d);add(l, d), add(r + 1, -d);}else{printf("%lld\n", sum(l));}}return 0; }
AcWing 243. 一个简单的整数问题2
输入样例:
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4
输出样例:
4 55 9 15
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio>using namespace std;typedef long long LL;const int N = 100010;int n,m; int a[N]; LL tr1[N]; //维护差分数组b[i]的前缀和 LL tr2[N]; //维护b[i] * i 的前缀和int lowbit(int x) {return x & -x; }void add(LL tr[], int x, LL c) {for(int i = x; i <= n; i += lowbit(i)) tr[i] += c; }LL sum(LL tr[], int x) {LL res = 0;for(int i = x; i; i -= lowbit(i)) res += tr[i];return res; }LL prefix_sum(int x) {return sum(tr1, x) * (x + 1) - sum(tr2, x); }int main() {cin >> n >> m;for(int i = 1; i <= n; i ++ ) scanf("%d",&a[i]);for(int i = 1; i <= n; i ++ ){int b = a[i] - a[i - 1];add(tr1, i, b);add(tr2, i, (LL)i * b);}while(m --){char op[2];int l,r,d;scanf("%s%d%d", op, &l, &r);if(*op == 'Q'){printf("%lld\n",prefix_sum(r) - prefix_sum(l - 1));}else{scanf("%d",&d);add(tr1, l, d), add(tr1, r + 1, -d);add(tr2, l, l * d), add(tr2, r + 1, (r + 1) * -d);}}return 0; }
AcWing 244. 谜一样的牛
输入样例:
5 1 2 1 0
输出样例:
2 4 5 3 1
// 找到一个最小的x是sum(x) = k
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 100010;int n;
int h[N];
int ans[N];
int tr[N];int lowbit(int x)
{return x & -x;
}void add(int x, int c)
{for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}int sum(int x)
{int res = 0;for(int i = x; i; i -= lowbit(i)) res += tr[i];return res;
}int main()
{cin >> n;for(int i = 2; i <= n; i ++ ) scanf("%d", &h[i]);for(int i = 1; i <= n; i ++ ) tr[i] = lowbit(i);for(int i = n; i; i -- ){int k = h[i] + 1;int l = 1, r = n;while(l < r){int mid = l + r >> 1;if(sum(mid) >= k) r = mid;else l = mid + 1;}ans[i] = r;add(r, -1);}for(int i = 1; i <= n; i ++) printf("%d\n", ans[i]);return 0;
}
【数据结构】—— 树状数组相关推荐
- js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree)
本文来源于力扣圈子,作者:胡小旭.点击查看原文 力扣leetcode-cn.com 树状数组或二叉索引树(英语:Binary Indexed Tree),又以其发明者命名为 Fenwick 树.其初 ...
- 数据结构——树状数组
我们今天来讲一个应用比较广泛的数据结构--树状数组 它可以在O(nlogn)的复杂度下进行单点修改区间查询,下面我会分成三个模块对树状数组进行详细的解说,分别是树状数组基本操作.树状数组区间修改单点查 ...
- 数据结构--树状数组
文章目录 1. 树状数组 2. 单点修改 3. 区间修改 4. 完整代码 5. 参考文献 1. 树状数组 类似数据结构:线段树(Segment Tree) 树状数组 跟 线段树 的区别: 树状数组能做 ...
- 2017西安交大ACM小学期数据结构 [树状数组 离散化]
Problem E 发布时间: 2017年6月28日 12:53 最后更新: 2017年6月29日 21:35 时间限制: 1000ms 内存限制: 64M 描述 给定一个长度为n的序列a ...
- 2017西安交大ACM小学期数据结构 [树状数组,极大值]
Problem D 发布时间: 2017年6月28日 10:51 最后更新: 2017年6月28日 16:38 时间限制: 1000ms 内存限制: 32M 描述 给定一个长度为n的序列a ...
- 2017西安交大ACM小学期数据结构 [树状数组]
Problem C 发布时间: 2017年6月28日 11:38 最后更新: 2017年6月28日 16:38 时间限制: 1000ms 内存限制: 32M 描述 给定一个长度为n的序列a ...
- 数据结构 —— 树状数组
[概述] 树状数组又称二叉索引树,常用于高效计算数列的前缀和.区间和,其查询.修改的时间复杂度为 log(n),空间复杂度为 O(n) 树状数组通过将线性结构转化成树状结构,从而进行跳跃式扫描. 优点 ...
- Java数据结构-树状数组
什么是树状数组?[面试5.0] 使用数组表示多叉树的结构,和优先队列有点类似,区别在于优先队列只表示二叉树 主要用来: 更新数组元素的数值并且求数组前K个元素的总和或平均值 时间复杂度为O(logN) ...
- “高级”数据结构——树状数组
数据结构是每一个程序员都必须要学的,非常重要! 大佬的博客写的真好,虽然我看不懂..... 链接http://www.cnblogs.com/RabbitHu/p/BIT.html
- 树状数组(单点+区间的所有操作)
转载:https://blog.csdn.net/I_believe_CWJ/article/details/80374326 更简洁方便的数据结构--树状数组(基于线段树的实现) 1.单点更新+区间 ...
最新文章
- noip复赛普及组2020_我校学子在2020年“外研社·国才杯”全国英语写作大赛(高职组)复赛中斩获佳绩...
- 第二十六篇 面向对象初识
- xp电脑怎么进入bios
- java线程安全例子_Java总结篇系列:Java多线程(三)
- 密码必须至少为6个字符_1081 检查密码 (15分)
- Linq的Distinct方法的扩展
- python入门基础系列八_03python—9个基础常识-python小白入门系列
- 3种方法实现Android按钮的点击事件,建议收藏!
- Full internet technology map. 最全的互联网技术图谱
- 【综述】详解ERNIE-Baidu进化史及应用场景
- 零基础的人也能学好C++
- 暗黑破坏神2 符文自动合成--按键精灵源码
- 贴片led极性_贴片发光二极管正负极判断方法详解
- 计算机中文件名无法更改原因,电脑系统文件夹名称修改不了怎么办
- PowerDesign license安装问题
- 国立台湾大学里的自动化书库(立体库)
- 升级工作环境并支持C++17
- java制作小鱼吃大鱼_大鱼吃小鱼游戏(Java编写)
- js 按拼音 首字母 排序 并分组
- Python之ffmpeg:利用python编程基于ffmpeg将m4a格式音频文件转为mp3格式文件
热门文章
- 愚人节,这样的微信公众号图文排版方式你见过吗?
- Arcgis中修改属性字段名
- 《Solar Energy Materials and Solar Cells》期刊介绍(SCI 2区)
- 自动登录163邮箱的批处理
- 无线网卡代理服务器连接失败怎么办,电脑用无线网卡连不上网的解决方法
- 睡眠伤害计算机硬件吗,电脑高手告诉您,电脑不关机只睡眠到底伤不伤硬盘?...
- 自己制作深度学习数据集教程
- Calendar类你可能不知道的坑
- react-native系列(11)组件篇:Image图片加载和ImageEditor图片剪切
- 当代考研人的发疯行为!笑到打鸣哈哈嗝哈哈嗝!