本文研究线段树的空间问题。
注意: 虽然下面给出了“空间复杂度”,但是不要按空间复杂度开!要按照“总结点不超过”开。下面把需要开的大小记作 T。
普通线段树
假设线段树需要维护区间 [1,n]。
结论:T=4n,用 N << 2 | 1。
也就是一共有 n 个叶子结点,最好情况下深度为 log2n+1,最坏情况下深度为 log2n+2。
所以总结点不超过 2log2n+2=4n,空间复杂度是 O(n)。
动态开点线段树
假设线段树需要维护区间 [1,n],总共要处理 m 次更新和查询(千万注意是两者之和!!!)。
结论:T<40m,用 (M << 5) + (M << 3)。
最坏情况下深度为 log2n+2,也就是每次更新 / 查询最多创建 log2n+2 个节点,总结点不超过 mlog2n+2m,空间复杂度是 O(mlog2n)。
然而计算 log 太麻烦了,我们尝试线性近似:
- 假设 mlog2n+2m≤km,待定 k。
- 两边约去 m,得 log2n+2≤k,左边肯定是单调递增的,代入 n=1011,log21011+2≈38.54,稍微取整一下,取 k=40。
一般也不太可能遇到 >1011 数量级的数据了吧……
类似地,我们得到下表。32m 和 40m 是常见的取值,别的看个乐就好。
| n≤ | 105 | 109(__int32 上界) | 1011 | 1012 | 1019(__int64 上界) |
|---|
| 空间估算(节点) | <20m | <32m, M << 5 | <40m,
(M << 5) + (M << 3) | <42m | <66m |
可持久化线段树
假设线段树需要维护区间 [1,n],总共要处理 m 次更新和查询。
结论:T<40m。
其实和动态开点线段树是差不多一样的。