数据结构——树状数组 学习笔记
数据结构——树状数组 学习笔记
引入
树状数组的特点:
- 好写好调。
- 一般只支持单点修改,前缀查询。
- 可以通过差分、公式等实现区间修改,单点查询等。
我们考虑这样一个题:
- 单调修改,区间求和。
我们有两个比较好想的思路:
- 直接 \(\mathcal O(1)\) 修改,\(\mathcal O(n)\) 遍历查询;
- 维护前缀和 \(\mathcal O(1)\) 查询,\(\mathcal O(n)\) 修改贡献。
而树状数组提供了一个每个操作单次 \(\mathcal O(\log n)\) 的做法。
基本思想
代数上,太复杂了我们不考虑。
几何上,如图,
我们令 \(s_i\) 表示,
- 从 \(i\) 往前数 \(\operatorname{lowbit(i)}\) 位的和,即 \(a(i-\operatorname{lowbit}(i)+1,,i)\)。
那么我们就知道,前缀和可以表示为若干个这样的区间。
可以发现,任何一个前缀都可以被 \(\mathcal O(\log n)\) 个小块表示,因此复杂度正确。
代码实现:
constexpr int N = 1e5 + 10; #define lowbit(x) ((x) & -(x)) int n, s[N]; // [1, x] int query(int x) { int r = 0; for (; x; x -= lowbit(x)) r += s[x]; return r; } // [x] += v int modify(int x, int v) { for (; x <= n; x += lowbit(x)) s[x] += v; } // [l, r] int query(int l, int r) { if (l == 1) return query(r); return query(r) - query(l - 1); }
请注意:
- 树状数组不支持负数及零下标,可以使用偏移量或者离散化;
- 树状数组本身只支持单点修改,前缀查询,可以通过数学方法来实现其他的。
差分实现区间修改,单点查询。
我们将原数组 \(s\) 变为其差分数组,那么,
- 区间修改,差分性质即可;
- 单点查询,注意到原数组即差分数组的前缀和,符合树状数组维护的性质。
代码实现:
int add(int p, int q, int v) { modify(p, v); modify(q + 1, -v); } int at(int x) { return query(x); }
区间修改,区间查询。
推式子,感觉不如线段树直接维护,略。
本文来自博客园,作者:RainPPR,转载请注明原文链接:https://www.cnblogs.com/RainPPR/p/18294901
如有侵权请联系我(或 2125773894@qq.com)删除。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战