线段树与离线询问
线段树与离线询问结合的问题在 OI 领域也有出现。这种技巧又被称为线段树分治。
假如你需要维护一些信息,这些信息会在某一个时间段内出现,要求在离线的前提下回答某一个时刻的信息并,则可以考虑使用线段树分治的技巧。
实际上线段树分治常用于不带删的数据结构转成可以带删的数据结构,抑或是对于某一个属性的信息分别计算。
过程
首先我们建立一个线段树来维护时刻,每一个节点维护一个 vector
来存储位于这一段时刻的信息。
插入一个信息到线段树中和普通线段树的区间修改是类似的。
然后我们考虑如何处理每一个时间段的信息并。考虑从根节点开始分治,维护当前的信息并,然后每到一个节点的时候将这个节点的所有信息进行合并。回溯时撤销这一部分的贡献。最后到达叶子节点时的信息并就是对应的答案。
如果更改信息的时间复杂度为
整个分治流程的总时间复杂度是
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
例题
luogu P5787 二分图/【模板】线段树分治
你需要维护一个
对于每一个时刻,若此时该图为二分图,输出 Yes
,否则输出 No
。
解题思路
使用种类并查集来维护一个图是否是二分图,然后就可以套用线段树分治了。
注意可撤销的并查集不能路径压缩,只能按秩合并。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
|
颜色限制 restriction
一个
对于每种颜色,请判断假如删去所有这种颜色的边,得到的图是否连通?是否是一棵树?
输出满足删去后图连通的颜色数和删去后图是树的颜色数。
解题思路
对于每一种颜色,建立一个时间,在这个时间内没有这个颜色的边,其他边都有。用一个并查集维护一下即可。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
|
luogu P4219 [BJOI2014] 大融合
需要维护一个
有
A x y
连边 。Q x y
输出经过边 的路径数。
允许离线。
解题思路
考虑允许离线,因此可以想到线段树分治。
然后考虑如何支持 Q 操作。如果不存在
因此你可以将 Q 拆成三个时间
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
|
luogu P2056 [ZJOI2007] 捉迷藏
出一个
C x
将第 个点的颜色反转。G
询问树上两个黑色点的最远距离。特别地,若不存在黑色点,输出 。
允许离线。
解题思路
首先考虑如何维护树上点集的直径,有下面的推论:
对于一个集合
和只有一个点的集合 。若集合 的直径为 。则点集 的直径只可能为 或 。
然后考虑解决原问题。我们可以考虑维护黑色点集,维护每一个点在黑色点集中的若干个时间段(具体你开一个桶记录一下上一次进入黑色点集的时刻即可)。
然后就自然地想到离线,将所有时间刻插入到线段树中。然后在线段树上分治,每次线段树上的点会记录当前时间段点集新增的点,新增点可以使用上面的推论,找到新点集直径的两个端点。
撤销是平凡的,开一个栈记录一下直径端点的变化即可。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
|
习题
- CF601E A Museum Robbery 线段树分治 + 背包 dp。
- CF19E Fairy 线段树分治 + 种类并查集。
- luogu P5227 [AHOI2013] 连通图 线段树分治 + 并查集。
- luogu P4319 变化的道路 线段树分治 + Link Cut Tree 维护最小生成树。
- luogu P3733 [HAOI2017] 八纵八横 线段树分治 + 线性基。
本页面部分内容参考自博文 Deleting from a data structure,版权协议为 CC-BY-SA 4.0。
本页面最近更新:2024/3/10 20:44:15,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:xiezheyuan, aofall, CoelacanthusHex, Enter-tainer, Great-designer, Kensuke-Hinata, Marcythm, Persdre, shuzhouliu, Tiphereth-A
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用