线段树入门

匿名 (未验证) 提交于 2019-12-02 23:49:02

1.我想单点查询序列的值,怎么办?
当然是来一个数组啦!

2.我想单点查询序列的值,还想单点修改,怎么办?
还是数组!

3.我想区间求和(后文称为查询),怎么办?
维护一个前缀和,\(sum[i]=\sum_{j=1}^ia[i]\)就可以\(O(1)\)查询。

4.我想区间求和,还想单点修改,怎么办?
退役吧。。

如果你至今还抱着万物皆可\(O(1)\)的幻想,那就\(Too\,young\,too\,simple\)了。

我来帮你复习一下:

1.OI\(\to\)计算机\(\to\)二进制\(\to O(log_2n)\)

2.\(OI \to \text{(幻视)} 01\to \text{二进制}\) \(\to\) \(O(log_2n)\)

“二进制”思想在算法中应用广泛,从二分到倍增等,都化\(n\)Ϊ\(log_2n\),避免了被卡飞的惨剧。所以就有了神奇的树状数组。

【注:你说差分?太强了,没听说过。】

5.现在毒瘤出题人要求你区间查询,区间修改。这类问题可以用线段树来解决。
听说你树状数组很6,甚至还会差分??


【注:图片来自百度百科,但是看上去百度百科也是侵权的w我就不删了】

图中的巨型树状物就是一颗线段树。也就是说,将一个大区间取中点得到小区间,组成一颗二叉树,这就叫线段树。

这和树状数组大同小异。将大区间拆成至多\(log_2n\)个小区间(n为区间总长),就可以拼凑出答案。实现方法是分治:如果孩子区间与所求区间有重叠,就继续向下查询,直到孩子区间包含在所求区间内,此时累加答案。

还真的是。那怎么办呢?我们先不考虑这个问题。

直接将对应的\(log_2n\)个节点修改就好了。
学到这里,你应该能A一道模板题了。

对于一个不在线段树最底层的区间,在修改时,我们要把他的孩子一起更新。此时应该思考两个问题:

(1)如果我不用查询,更新孩子干嘛?

(2)如果我修改上了瘾,为什么不能把修改的内容累计,等到最后一起修改?

它们分别说明:

(1)要查询了,再来修改。

(2)不查询时,记录修改即可。

于是我们对于每一个节点,都记录一个标记\(tag\),在更新时只修改父亲节点的值,并把修改的内容记录到\(tag\)里。当查询到该节点时,顺手把子节点更新并下传标记。这样就不用连着孩子更新。
模板题

有时候维护的内容较多,就需要更复杂的代码。当然这些也属于模板题。

比如

(19-7-21未完待续)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!