1. 1. 板子
    1. 1.0.1. 1.【模板】线段树 1
    2. 1.0.2. 2.【模板】线段树 2
  • 2. 线段树结构分析
    1. 2.0.1. 1.[THUPC2021 初赛] 线段树
    2. 2.0.2. 2.[ZJOI2017] 线段树
    3. 2.0.3. 3.[ZJOI2019] 线段树
    4. 2.0.4. 4.[ZJOI2020] 传统艺能
  • 3. 扫描线
    1. 3.0.1. 1.【模板】扫描线
    2. 3.0.2. 2.[IOI1998] [USACO5.5] 矩形周长Picture
    3. 3.0.3. 3.[SDOI2009] HH的项链
  • 4. 可持久化线段树
    1. 4.0.1. 1.【模板】可持久化线段树 2
    2. 4.0.2. 2.Rmq Problem / mex
    3. 4.0.3. 3.[CQOI2015] 任务查询系统
    4. 4.0.4. 4.Destiny
  • 5. 线段树合并
    1. 5.1. 树上问题
      1. 5.1.1. 1.雨天的尾巴
      2. 5.1.2. 2.[NOIP2016 提高组] 天天爱跑步
    2. 5.2. 整体 DP
      1. 5.2.1. 1.[PKUWC2018] Minimax
      2. 5.2.2. 2.[NOI2020] 命运
  • 6. 线段树分裂
    1. 6.0.1. 1.【模板】线段树分裂
  • 7. 树套树
  • 8. 李超线段树
    1. 8.0.1. 1.【模板】李超线段树 / [HEOI2013] Segment
    2. 8.0.2. 2.丝之割
    3. 8.0.3. 3.Escape Through Leaf
    4. 8.0.4. 4.Sum of Prefix Sums
  • 9. 线段树维护矩阵
    1. 9.1. 序列问题
      1. 9.1.1. 1.Bear and Cavalry
    2. 9.2. 树上问题
      1. 9.2.1. 1.【模板】”动态 DP”&动态树分治
      2. 9.2.2. 2.[ZJOI2019] Minimax搜索
  • 10. 线段树维护树上信息
    1. 10.1. 维护直径
      1. 10.1.1. 1.[CEOI2019] Dynamic Diameter
      2. 10.1.2. 2.Tree Generator™
    2. 10.2. 维护最小连通子树
      1. 10.2.1. 1.[SDOI2015] 寻宝游戏
      2. 10.2.2. 2.[ZJOI2019] 语言
  • 11. 线段树优化建图
    1. 11.0.1. 1.Legacy
    2. 11.0.2. 2.「JOISC 2020 Day4」治疗计划
  • 12. 单侧递归线段树
  • 13. 线段树分治
    1. 13.0.1. 1.二分图 /【模板】线段树分治
    2. 13.0.2. 2.Painting Edges
  • 14. 线段树维护历史值 & segment tree beats
  • 15. KTT
  • 16. 参考
  • 线段树进阶

    板子

    1.【模板】线段树 1

    code

    2.【模板】线段树 2

    code

    线段树结构分析

    1.[THUPC2021 初赛] 线段树

    $[1,n]$ 上的广义线段树内 $[l,r]$ 的最小拆分大小为 $2(r-l+1)-|S|$,其中 $S$ 为包含于 $[l,r]$ 的线段树节点。

    证明

    将包含于 $[l,r]$ 的线段树节点取出,形成满二叉树森林,根节点的个数为最小拆分大小。
    叶子节点的个数为 $r-l+1$,那么 $|S|=2(r-l+1)-根节点的个数$。

    2.[ZJOI2017] 线段树

    $[l,r]$ 的拆分可以看成 $[l-1,l-1],[r+1,r+1]$ 与二者 lca,的路径的左/右儿子。

    不想写了。。。

    3.[ZJOI2019] 线段树

    对点分类。。。

    4.[ZJOI2020] 传统艺能

    扫描线

    这是一种思想。狭义上更偏向于计算几何。

    1.【模板】扫描线

    code 这里也可以维护区间最小值及其个数。

    2.[IOI1998] [USACO5.5] 矩形周长Picture

    code

    3.[SDOI2009] HH的项链

    区间 $[l,r]$ 转化为点 $(l,r)$,发现只需求每个点被覆盖个数,扫描线+树状数组实现。

    事实上单纯从左到右扫描,用线段树动态维护信息就是扫描线思想了。这题也可以这样理解。

    可持久化线段树

    1.【模板】可持久化线段树 2

    对下标扫描线,构建可持久化权值线段树。

    2.Rmq Problem / mex

    权值线段树维护每个值最后出现的位置。离线扫描线或可持久化线段树均可。

    3.[CQOI2015] 任务查询系统

    对时间扫描线,用权值线段树维护优先级,由于强制在线,用可持久化线段树即可。

    4.Destiny

    类似绝对众数为排序后第 $\left \lceil \frac{n}{2} \right \rceil$ 个元素。

    记 $d=\left \lceil \frac{r-l+1}{k} \right \rceil$,查询区间第 $d,2d,…$ 大,判断次数是否符合即可。

    可持久化线段树维护,时间复杂度 $O(kn\log n)$。

    线段树合并

    需要考虑的是两个叶子节点的合并和如何只取一个节点。

    树上问题

    1.雨天的尾巴

    code

    2.[NOIP2016 提高组] 天天爱跑步

    可以把玩家拆成向上和向下的两条链,两条链时间均递减/增,与深度联系一下就能转化为雨天的尾巴。

    整体 DP

    对于树上 DP 问题,可用线段树维护其中一维,加入子节点时用线段树合并转移,可以优化时间和空间。

    1.[PKUWC2018] Minimax

    所有叶子节点都有概率被取到,先离散化一下,计算出根节点取第 $i$ 小权值的概率即可计算答案。

    记 $f[u][i]$ 为 $u$ 节点取 $i$ 号权值(即为第 $i$ 小)的概率。由于子节点数小于 $2$ ,可以分讨一下

    • 若 $u$ 为叶子节点,直接更新。
    • 若 $u$ 只有一个子节点,直接取子节点的值。
    • 若 $u$ 有两个子节点。

    可以前缀和后缀和优化 $O(n^2)$ 暴力计算。

    考虑权值线段树维护第二维区间和(其实就是概率和)。需要合并两个子节点的值,考虑其中一个节点为空的情况,发现另一个节点的所有值都需要乘同一个值,写一个区间乘即可。具体实现时,一边合并,一边记录前缀后缀和。

    2.[NOI2020] 命运

    考虑树上 DP。在枚举 $u$ 点时,需要管的链肯定是下端点在子树中且未被满足的,此时应考虑 $u$ 到子节点的边的取值。

    不难发现只需要考虑上端点在 $u$ 上方且深度最大的链,如果它被满足,则其他所有链都被满足(在 $u$ 上方这个限制不用特意注意)。

    可以记 $f(u,i)$ 为下端点在 $u$ 的子树内且未被满足的链的上端点的最大深度为 $i$ 的方案数。每次加一个子节点转移

    与前缀和有关,且开始有值的点很少,用线段树合并优化。具体实现时在 merge 中记录两棵线段树的前缀和可以减少查询的 $\log$。对于 $sum(u,i-1)$ 在有个节点为空时不需要管,因为空节点值为 $0$。当 $l=r$ 时,需要考虑,应该后更新该节点的前缀和。时间复杂度 $O(n\log n)$。

    线段树分裂

    1.【模板】线段树分裂

    code 还可以平衡树合并。

    树套树

    详见

    李超线段树

    支持插入线段,查询某位置交点最值。

    1.【模板】李超线段树 / [HEOI2013] Segment

    code

    2.丝之割

    为了方便,先将第一行反转一下,并将线的位置加 $1$。一些被包含的线是没用的将其去掉。剩下的按第一行的位置排序,第二行的位置是单减的。

    考虑 DP,记 $f(i)$ 为处理到第 $i$ 个的最小花费。转移显然可以斜率优化。用李超线段树即可,时间复杂度 $O(n\log n)$(是单 $\log$ 因为是插入直线)。

    3.Escape Through Leaf

    暴力树上 DP 显然,用李超线段树合并维护。线段树合并的时间复杂度是 $O(n\log n)$ 的,第一篇题解有势能分析。

    dsu on tree 可以做到 $O(n\log^2n)$。

    4.Sum of Prefix Sums

    有点类似直径,但是很复杂,不能 DP 或贪心。考虑点分治,合并路径时用李超线段树。时间复杂度 $O(n\log^2n)$。

    线段树维护矩阵

    序列问题

    1.Bear and Cavalry

    树上问题

    1.【模板】”动态 DP”&动态树分治

    如果没有修改,我们可以简单用 DP 求解。记 $dp(u,0/1)$ 为 $u$ 的子树,$u$ 选或不选的最大独立集,有

    对于每个点选出一个特殊的子节点 $x$,记 $f_u=\sum_{v \ne x} \max(dp(v,0),dp(v,1))$,$g_u=\sum_{v \ne x}dp(v,0)+a[u]$。那么有

    写成 $(\max,+)$ 广义矩阵乘法的形式就是

    令 $x$ 为 $u$ 的重儿子,用线段树维护矩阵乘法,那么修改一个点,只会对 $O(\log n)$ 条重链造成影响。

    code

    2.[ZJOI2019] Minimax搜索

    限制是取 $\max$ 的形式,考虑求出 $\max \le k$ 的方案数再差分。
    考虑如何对单个 $k$ 快速求出答案。

    记 $dp_u$ 为没有变化时 $u$ 点的值。那么 $1 \to dp_1$ 形成了一条 $dp$ 值都为 $dp_1$ 的链,只要链上任意节点的 $dp$ 值改变,答案一定改变。

    对于叶子节点 $u$,若 $dep_{lca(u,dp_1)}$ 为奇数,那么若改变 $u$,则 $dp_u$ 变为 $dp_u + k$,偶数同理。

    记 $f_u$ 为可以使 $dp_u \le dp_1$ 的方案数(叶子节点需要特判)$cnt_u$ 为 $u$ 子树中总方案数。答案为

    $f$ 也是好计算的,就可以 $O(n)$ 求出特定 $k$ 的答案了。随着 $k$ 的变化,变化的 DP 值为某几个叶子节点,考虑动态 DP。记

    这样转移式子优化为一个形式,动态 DP,时间复杂度 $O(n\log^2n)$。

    线段树维护树上信息

    维护直径

    1.[CEOI2019] Dynamic Diameter

    贪心

    并集的直径端点一定在原四个端点中,线段树维护即可。时间复杂度 $O(n\log^2n)$,$O(1)$ 求 lca 可以优化到 $O(n\log n)$。

    注意:贪心只有在边权非负的情况下才是对的。

    code

    dfs 序

    一个节点无论访问还是回溯都记录下来,这样会得到一个长为 $2n-1$ 序列( $rt$ 出现次数为$deg[rt]+1$ ,其他点出现的次数为 $deg[u]$ ),即为树的 dfs 序。

    它有一个很好的性质:将原节点记为第一次出现的位置,则 $\min_{i=u}^{v} dep[i] = dep[lca(u,v)]$ ,考虑 dfs 过程不难理解。那么 $dis(u,v)=dep[u]+dep[v]-2\min_{i=u}^{v} dep[i]$。

    用线段树维护直径 $s$,$\min_{u}dep[u]$,$\max_{u}dep[u]$,$\max_{u}\{dep[u]-2\min_{i=l}^{u}dep[i]\}$,$\max_{u}\{dep[u]-2\min_{i=u}^{r}dep[i]\}$。

    注意:该方法仅适用于边权非负,这样才能保证区间中 dep 最小的点为 lca。

    code

    2.Tree Generator™

    括号序列

    构造一棵树的括号序列:dfs,向下就加‘(’,向上就加‘)’ 。长度为 $2*n-2$ ,因为每条边会被访问两次

    • 性质一: 一段括号序列去掉对应的括号对应树的一条链(思考 dfs 过程)。

    • 性质二: 一段括号序列去掉对应的括号所得序列的长度记为树上链的长度。

    去掉对应括号的序列只有三种

    • ))))))…

    • ((((((…

    • )))…(((

    考虑一般化,将‘(’视为 1, ‘)’视为 -1 ,则该链的长度为 $\max_{i=l-1}^{r}\{v(i+1,r)-v(l,i)\}$。直径即为最大的链长,类似最大子段和,用线段树维护。

    code

    维护最小连通子树

    给定 $n$ 个关键点,动态维护 $n$ 个关键点所形成的最小连通子树大小。

    将n个点按dfn序从小到大排序为 $0,2,…,n-1$ ,则子树大小为 $\frac{1}{2}\sum_{i=0}^{n-1}dis(i,(i+1)\%n)$。

    1.[SDOI2015] 寻宝游戏

    线段树

    一般用于关键点

    考虑如何合并,拆一下 $\%$

    有点麻烦,考虑不维护 $dep[lca(l,r)]$

    简单多了,最后减去即可。时间复杂度 $O(n\log^2n)$ , $O(1)$ 求 lca 可做到 $O(n\log n)$。

    code

    set

    非常简单的做法,直接维护最开始的式子,记 $ans$ 为最终答案。

    每次加入 $u$ ,则 $ans+=dis(pre(u),u)+dis(u,nxt(u))-dis(pre(u),nxt(u))$。

    每次减去 $u$ ,则 $ans+=dis(pre(u),,nxt(u))-dis(pre(u),u)-dis(u,nxt(u))$。

    需要加入删除一个数,求前驱后继,用平衡树维护即可(可以用 set)。

    code

    2.[ZJOI2019] 语言

    对于两元关系的统计,先固定一点 $u$,考虑如何求出 $(u,x)/(x,u)$ 的数量。

    将所有经过 $u$ 的路径赋值为 1 ,统计 1 的个数,除以二即为答案。

    树上的若干条链,经过同一个点,那么就形成了一个连通子树。

    对于每个节点,我们都可以用线段树来维护最小连通子树。

    差分,然后线段树合并即可,时间复杂度 $O(n\log^2n)$ ,同上可以优化为 $O(n\log n)$。

    code

    线段树优化建图

    一般优化三种连边

    • $x \to [l,r]$

    • $[l,r] \to x$

    • $[l,r] \to [l’,r’]$

    主要思想是建虚点代表一个区间。

    1.Legacy

    建一棵根向线段树,一棵叶向线段树。

    我的 dij 板子怎么是错的???

    code

    2.「JOISC 2020 Day4」治疗计划

    $O(m^2)$ 是简单的。考虑优化,套路地想数据结构优化。拆一下绝对值,如果 $i \to j$,那么

    • $t_j<t_i: r_i-t_i+1 \ge l_j-t_j$.

    • $t_j>t_i: r_i+t_i+1 \ge l_j+t_j$.

    由于连向某个点的权值都相同,所以每个点在被枚举到时其 $dis$ 就已经确定。考虑快速找出邻点,这样均摊是对的。先按 $t$ 排序,然后线段树,时间复杂度 $O(n\log n)$。

    单侧递归线段树

    详见

    线段树分治

    不如叫基于时间的分治。

    1.二分图 /【模板】线段树分治

    2.Painting Edges

    一棵树,每条边有颜色(开始没有),当加入任意一种颜色的边时,图都为二分图,则此时合法。每次操作改变某条边的颜色,只有当改变后合法才会进行,判断每次操作是否会进行。

    颜色很少,考虑对每个颜色开一个并查集维护。

    我们并不能将操作离线下来,但每个时间只有一次操作,可以按时间先后线段树分治,先将操作挂在对应的叶子节点上,递归到该点时判断是否合法,并将对应区间进行覆盖(原颜色或更改的颜色)。

    由于每次操作后图一定合法(不然不会操作),所以在叶子节点只需判断加入挂着的边后是否合法即可。

    时间复杂度 $O(m\log q\log n+nk)$。

    注意:不要手写栈,因为实际加入堆的元素个数为 $2(拆后的总边数)$ 而手写栈要开到 $2k(拆后的总边数)$ 空间会炸。

    code & data_maker

    线段树维护历史值 & segment tree beats

    详见

    KTT

    详见

    参考

    线段树相关技巧的小小总结(修订版)

    线段树进阶 Part 1