各种数据结构以及七七八八的东西
堆
堆(一般指二叉堆),实质就是一颗完全二叉树,用来维护单调性
堆可以实现插入新值,得到最值(直接取堆顶值),删除最值。
插入新值,从堆尾插入,不断比较 上浮;删除最值,就是将堆顶替换掉,可以用堆尾 替换,并不断比较 下沉,用树的深度的时间花销维护堆的单调性
感受一下维护堆的过程,可以用数组实现(一一对应),手写堆就很容易写
手写堆 code
inline void up(int u) { if (u / 2 && a[u / 2] > a[u]) swap(a[u], a[u / 2]), up(u / 2); } inline void down(int u) { int v = u; if (u * 2 <= cnt && a[u * 2] < a[u]) v = u * 2; if (u * 2 + 1 <= cnt && a[u * 2 + 1] < a[v]) v = u * 2 + 1; if (v != u) swap(a[u], a[v]), down(v); } inline void push(int x) { a[++ cnt] = x; up(cnt); } inline void pop() { a[1] = a[cnt]; cnt --; down(1); }
priority_queue
就是 STL 里封装好的堆(默认大根堆)
另外,由于这个用堆尾替换堆顶的等价操作(等价于删除堆顶操作),两个相等的元素可能位置会有变化,即后进堆的可能深度更浅一些,所以,堆排序是不稳定的
对于某一种排序算法,如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序保持不变,那么就说这个排序算法是稳定的。
这里我们从 rmq 问题开始,讨论 st表(有点简单且扩展差,略)、树状数组、线段树。。。甚至分块
先放个表格对比一下,一些基础操作
算法 | 预处理 | 单点查询 | 单点修改 | 区间修改 |
---|---|---|---|---|
朴素算法 | 无 | |||
st 表 | 不支持 | 不支持 | ||
树状数组 | 结合差分可以做到 |
|||
线段树 | ||||
分块 |
树状数组
tip:lowbit(x) 的作用是返回
从右往左第一个为 1 的数,即若 1 第一次出现的位置为 p,则返回 实现方法就是对
先取反,再 + 1,得到 ,发现两二进制数在第一个 1 及右边的 0 是完全相同的,但是左边仍是对应取反的,此时可以 得到结果 计算机中,刚好一个数的负数就是按照其补码 + 1 存储的,所以等价于
树状数组同样可以同时维护 区修 + 区查,
在差分思想的基础上,若查询原数组
到最后一个式子就把不同的变量分离了,实现更简单,
注意:树状数组中的下标不是原数组的下标,在
code
int lowbit(int x) { return x & (-x); } void add(int x, int k) { int p = x; for (; x <= n; x += lowbit(x)) { c1[x] += k; c2[x] += k * p; } } int query(int x) { int ans = 0, p = x; for (; x ; x -= lowbit(x)) ans += (p + 1) * c1[x] - c2[x]; return ans; } void init() { for (int i = 1; i <= n; i ++) { b[i] = a[i] - a[i-1]; add(i, b[i]); } } void get_add(int x, int y, int k) { add(x, k); add(y + 1, -k); } int get_query(int x, int y) { return query(y) - query(x - 1); }
分类:
D 数据结构 - 线段树 / 树状数组
, A 学习笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具