线段树学习笔记

来源:互联网 发布:sqlserver 服务器别名 编辑:程序博客网 时间:2024/06/05 07:39

学习资料

线段树从零开始
线段树详解

笔记本

①支持点修改、区间修改(线段树中最有用的)、区间查询,只是查询某个点的话不需要线段树
②线段树是二叉树,其编号必须从1开始,可以用数组来保存。简单的记法: 足够的空间 = 数组大小n的四倍。 实际上足够的空间 = (第一个比n大的2的幂次)的两倍。
③rt为结点的编号,则rt << 1为rt的左儿子,rt << 1 | 1为rt的右儿子
④主要用于高效解决连续区间的动态查询问题。更具体些,有区间最值查询问题,连续区间修改或者单节点更新的动态查询问题,多维空间的动态查询问题
⑤构造方法:结构体
⑥常见标记:赋值标记、加标记、乘标记、等差数列标记、翻转标记(01翻转,左右翻转)
⑦当我们进行单点修改的时候显然可以直接找到叶子节点进行修改然后在回溯的过程中更新节点信息,但是当我们进行区间修改的时候就需要一个新的帮手:懒(Lazy)标记。
⑧线段树的题目整体上可以分成以下四个部分:
单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来
成段更新(通常这对初学者来说是一道坎):需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候
区间合并:这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并
扫描线:这类题目需要将一些操作排序,然后从左到右用一根扫描线(当然是在我们脑子里)扫过去。最典型的就是矩形面积并,周长并等题。
多棵线段树问题:此类题目主要特点是区间不连续,间隔有一定规律,用多棵树表示不同的偏移区间
⑨注意mid的求法,(l + r)/2 可能会溢出,(l+ (r- l) ) >> 1 这样比较好。(注意位运算操作符的优先级较低)
⑩应用线段树的条件:满足区间加法
数字之和——总数字之和 = 左区间数字之和 + 右区间数字之和
最大公因数(GCD)——总GCD = gcd( 左区间GCD , 右区间GCD );
最大值——总最大值=max(左区间最大值,右区间最大值)
不符合区间加法的例子:
众数——只知道左右区间的众数,没法求总区间的众数
01序列的最长连续零——只知道左右区间的最长连续零,没法知道总的最长连续零
⑪线段树对于每个n的分解是唯一的,所以n相同的线段树结构相同,这也是实现可持久化线段树的基础。
⑫假设要修改[5]的值,可以发现,每层只有一个节点包含[5],所以修改了[5]之后,只需要每层更新一个节点就可以线段树每个节点的信息都是正确的
⑬有的标记之间会相互影响,所以比较简单的做法是,每递归到一个区间,首先下推标记(若本节点有标记,就下推标记),然后再打上新的标记,这样每个区间操作的复杂度仍然是O(logn)。
⑭非递归线段树只能维护相对标记。
⑮标记永久化在二维线段树中就尤为重要,有些标记是可以永久化的,就比如说加标记,所谓标记永久化,就是在修改的时候在对应节点上加上这么一个标记,然后此标记不下推,但是要更新父亲节点的信息,在查询一个节点的权值时候从上到下加起来每一个父亲节点的标记,从而推出该节点正确的权值
⑯正常来说,区间改值,当更改某个区间的值的时候,子区间也该跟着更改,这样容易TLE。Lazy思想就是更新到某个区间的时候,就先给这个区间打上标记,标记内容是需要更新的值,并把子区间的值改为子区间对应的值,清除该区间的lazy标记;然后return,不去更新子区间。当下一次更新或查询等需要访问该区间的子区间的时候再把该区间的lazy和其他信息送回子区间。

原创粉丝点击