线段树合集
点击标题可进入题目链接
【1】入门
如图,一棵树由每个节点(node)组成,每个节点代表了数组[x-y]区间内的和;
每一个节点又是由子节点组成,子节点有左子节点和右子节点,如果当前节点为1,那么他的字节点为2和3,即:
节点A,左子节点为A*2,右子节点为A*2 + 1;
我们建一棵树为tree,原数组设为arr;
那么tree[node]=tree[node*2]+tree[node*2+1];(当前节点是两个子节点的和)
寻找每个节点的值,就要看子节点的值,这就用可以递归实现了。
时间复杂度为O(logn)
注意!
tree必须开4倍arr的大小,线段树是平衡二叉树,开4倍可以处理最坏情况——完美二叉树。
实现代码:
1 |
|
【2】华为2016校招笔试题
思路:
就是线段树,入门是求一段区间内的总和,这次换成求max值。
注意:
- 本题求一段区间可能1-5,也可能5-1,所以输入后要处理一下,不然就会WA哦。
- 多组输入。
- 4倍别忘了。(由于忘记开4倍,可怜的zser又被我叨扰了)
AC代码:
1 |
|
【3】HDUoj:敌兵布阵
思路:
就是线段树,最基础的板子题。
注意:
- cin,cout会T!很难受!
AC代码:
1 |
|
【4】HDUoj:I Hate It
思路:
跟第二题除了数组大小没有任何区别了。主要用于练手,练熟线段树写法。
注意:
- cin,cout会T。
AC代码:
1 |
|
【5】进阶:延迟标记——区间修改
1.理解懒标
延迟标记——懒标,用于解决区间修改,入门是更新某一个点,而懒标可以实现区间更新,比如要求区间[a,b]之间所有值加一,用懒标标记可以大大减少时间复杂度。
现在我们的树用结构体来建:
1 |
|
(当然也可以开数组,看个人习惯叭,不开结构体只需要两个数组,一个lazy数组,一个tree数组,我感觉是比结构体更节省空间的。不知道单开数组和递归传递数哪个更耗空间。)
2.懒标下放
懒标下放是最重要的,但是也很好理解,就是在需要的时候,把本来应该传下去,但是偷懒没有传下去的值传下去,当然,只有在查询和修改线段树时懒标才会用下放,因为建树根本没用上。
代码很好理解,只有三步(如果这里看不懂,总结里写了三步具体是什么):
1 |
|
3.总结
参上拙略总结:
代码:
1 |
|
【6】HDUoj:Just a Hook
思路:
区间修改,这个的话很容易发现,懒标不需要相加,是直接替换,所以在基础上改一改就能AC了。
注意:
结构体初始化。
一点搞笑题外话:写这个题的时候没注意自己开的中文翻译模式,然后直接复制的中文输出去提交,WA了,给我整蒙了还哈哈哈,结果才发现输出应该是英文。
AC代码:
1 |
|
【7】HDUoj:Atlantis
缠了我差不多一个月,我是笨比!!!
离散化+扫描线+线段树
题意:
给定方块的左下角和右上角,形成一个方块,有很多不同的方块,求最后形成的图形的总面积。(如图所示)
思路:
定义线段树来维护底边长和覆盖边数:
- len:底边长
- vis:覆盖边数
扫描线有l,r,h,vis属性:
- l,r:区间
- h:高(两条扫描线的高度差就是当前面积的高了)
- vis:定义当前扫描线是图形的底边还是顶边。
图形最终就是由扫描线扫过的小面积,底边*高,最后每个扫过的图形面积相加。
代码:
1 |
|
- 本文作者:lybbor
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!