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我就不删了】
图中的巨型树状物就是一颗线段树。也就是说,将一个大区间取中点得到小区间,组成一颗二叉树,这就叫线段树。
三、毒瘤操作 1.区间查询这和树状数组大同小异。将大区间拆成至多\(log_2n\)个小区间(n为区间总长),就可以拼凑出答案。实现方法是分治:如果孩子区间与所求区间有重叠,就继续向下查询,直到孩子区间包含在所求区间内,此时累加答案。
2.区间修改 woc这是\(O(n)\)!还真的是。那怎么办呢?我们先不考虑这个问题。
2.1单点修改很水直接将对应的\(log_2n\)个节点修改就好了。
学到这里,你应该能A一道模板题了。
对于一个不在线段树最底层的区间,在修改时,我们要把他的孩子一起更新。此时应该思考两个问题:
(1)如果我不用查询,更新孩子干嘛?
(2)如果我修改上了瘾,为什么不能把修改的内容累计,等到最后一起修改?
它们分别说明:
(1)要查询了,再来修改。
(2)不查询时,记录修改即可。
于是我们对于每一个节点,都记录一个标记\(tag\),在更新时只修改父亲节点的值,并把修改的内容记录到\(tag\)里。当查询到该节点时,顺手把子节点更新并下传标记。这样就不用连着孩子更新。
模板题
有时候维护的内容较多,就需要更长复杂的代码。当然这些也属于模板题。
比如
更复杂的查询
更复杂的修改
奇怪的维护内容
(19-7-21未完待续)