各种数据结构以及七七八八的东西
堆
堆(一般指二叉堆),实质就是一颗完全二叉树,用来维护单调性
堆可以实现插入新值,得到最值(直接取堆顶值),删除最值。
插入新值,从堆尾插入,不断比较 上浮;删除最值,就是将堆顶替换掉,可以用堆尾 替换,并不断比较 下沉,用树的深度的时间花销维护堆的单调性
感受一下维护堆的过程,可以用数组实现(一一对应),手写堆就很容易写
手写堆 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表(有点简单且扩展差,略)、树状数组、线段树。。。甚至分块
先放个表格对比一下,一些基础操作
算法 | 预处理 | 单点查询 | 单点修改 | 区间修改 |
---|---|---|---|---|
朴素算法 | 无 | \(O(n)\) | \(O(1)\) | \(O(n)\) |
st 表 | \(O(n\log n)\) | \(O(1)\) | 不支持 | 不支持 |
树状数组 | \(O(n)\) | \(O(\log n)\) | \(O(\log n)\) | 结合差分可以做到 \(O(\log n)\) |
线段树 | \(O(n)\) | \(O(\log n)\) | \(O(\log n)\) | \(O(\log n)\) |
分块 | \(O(n)\) | \(O(\sqrt n)\) | \(O(\sqrt n)\) | \(O(\sqrt n)\) |
树状数组
tip:lowbit(x) 的作用是返回 \((x)_2\) 从右往左第一个为 1 的数,即若 1 第一次出现的位置为 p,则返回 \(2^p\)
实现方法就是对 \((x)_{2}\) 先取反,再 + 1,得到 \((y)_2\) ,发现两二进制数在第一个 1 及右边的 0 是完全相同的,但是左边仍是对应取反的,此时可以 \(x \& y\) 得到结果
计算机中,刚好一个数的负数就是按照其补码 + 1 存储的,所以等价于 \(x\&(-x)\)
树状数组同样可以同时维护 区修 + 区查,
在差分思想的基础上,若查询原数组 \(a\) 的 \([1,p]\) 的区间和,则有:
到最后一个式子就把不同的变量分离了,实现更简单,\(b[i]\cdot i\) 可以再建一个树状数组代替。
注意:树状数组中的下标不是原数组的下标,在 \(p\) 这个位置上加,所以是\(\times p\) ,而不是 \(\times x\)
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);
}