线段树总结

线段树

你说的对,但线段树是一种用 \(O(n \cdot log \ n)\) 的大常数复杂度+略微的卡常下技巧=AC 的妙妙数据结构。

线段树是基于分治与二叉树的在线工具,可以维护区间信息,但比树状数组能够维护的东西更多。

线段树虽然能够维护的东西更多,但也有一些特别显著的缺点:

  • 代码量过长。
  • 查错不好查。
  • 大常数超时。

线段树其所对应的时空复杂度对应 $n \in [10^5,5\times 10^5] $。

在线段树中,节点的左儿子为 \(2x\) ,右儿子为 \(2x+1\)

一些易错点

线段树数组要乘 \(4\)

原因:

线段树是一种二叉树结构,其结构若为完全二叉树,则其所需空间为:

\( 1+2+4+......+n/4+n/2+n=2n-1 \)

但是实际应用中最后一层远远铺不满,所以最后一层的编号用不全,最坏情况是只用了最后一层的最后一个,为上一层编号再 \(\times 2\),所以要乘上 \(2 \times 2=4\) 倍。

线段树在修改与查询时,查询区间不变

比较常犯的一个错误,因为写 build(int p,int l,int r) 时,l 代表当前区间左端点,r 代表区间右端点,所以递归时要 build(p*2,l,mid)build(p*2+1,mid+1,r)

但是在修改与查询中 ask(int p,int l,int r) 中,lr 代表查询区间的左右端点,算是定值,不能更改。

在询问与修改中,\(mid=(l+r)>>1\)

很明显的一个错,但总是查不出来。

应该为 \(mid=(seg[p].l+seg[p].r)>>1\)

在修改中,为往上更改节点所存的值。

不必多言,注意了也经常错。

在建树(build 函数)时,没有 return

当你犯过一次并为此投入 \(1.5 h\) 的代价后,你会记住的.......

$ {\tiny 真实事件改编而来} $

To Be Continued

以下提供线段树查错思路

以上四种错误(除第 \(4\) 种)都会导致 \(RE(Segmentation\ \ fault\ \ with \ \ invalid \ \ memory \ \ reference.)\),如下。

如果不是 \(RE\),建议查其他错误。

建议:

  • 先查线段树数组是否 \(\times 4\)
  • 查询问与更改时,函数参数是否发生了不对的变化,见上第 \(2\) 点。
  • 同时检查第 \(3\) 点。
  • 最后再看 build 函数。

例题

【线段树模板题】序列操作1

板子。

F - Second Largest Query

进行分类讨论,我们也可以选择排序后选前两大,思维上难度较小。

A Simple Problem with Integers

懒惰标签板子。

维护序列-区间乘与区间加

维护两个懒惰标签,形如:
\( k\times mul+add \)

区间加可直接加,区间乘需要将 \(add\) 同时乘。

花神游历各国

结论题,注意到 \(a \le 10^9\) 只够开平方 \(5\) 次,前 \(5\) 次可暴力做,后面可以打个标签。

注意:

特殊判断 \(a_i\) 是否为 \(0\)

无聊的序列

差分之,操作一等效为区间加;操作二等效为区间求和。

E - Simple String Queries

线段树中维护 bitset

G - Smaller Sum

线段树中维护 vector


动态开点

posted @ 2025-01-02 20:16  Air2011  阅读(91)  评论(0)    收藏  举报