首页 > 其他 > 详细

线段树相关

时间:2021-06-14 23:40:24      阅读:46      评论:0      收藏:0      [点我收藏+]

线段树合并

  • 合并流程:

    需要将 \(u\), \(v\) 所代表的区间 \(l,r\) 进行合并。

    如果 \(u\)\(v\) 至少一个不存在,返回 \(u|v\)

    如果 \(l=r\),直接把 \(v\) 的信息合并到 \(u\),并返回 \(u\)

    否则将 \(u\)\(v\) 左右儿子分别合并为 \(u\) 的儿子,返回 \(u\)

    记得访问儿子前下放标记,结束后更新自己。

时间复杂度为 \(n\log n\)\(n\log n\) 为初始点数。

  • 证明:

    每次合并的花费为 \(k\)\(k\) 为重合的结点数,合并后会使总点数减少 \(k\),而总点数非负。

    所以复杂度与总点数同阶,为 \(O(n\log n)\)

一般用于优化有关树的 dp,维护子树信息 的问题。

例题

1.【NOI2020】命运

考虑 dp,设 \(f_{u,i}\) 表示终点在子树 \(u\) 内部的点对,还没有被满足的点对深度最深的恰好为 \(i\) 的方案数。

\[f_{u,i} = \sum_{j < i} f‘_{u,j}*f_{v,i} + \sum_{j \le i} f‘_{u,i}*f_{v,j} \]

再讨论 \(u\) 是否选择,\(f_{u,0} = f_{u,0} + \sum_{i\ge 0} f_{u,i}\)

于是在线段树合并的时候完成 \(v\)\(u\) 的更新,只需线段树维护区间 \(f\) 的和。

从左往右进行合并,合并时维护当前区间 \(l...r\) 的前缀 \(f_{0...l-1}\) 之和即可。

线段树分裂

有些问题只对一段区间 \(l...r\) 进行复杂的操作,于是需要把线段树 \(l...r\) 的部分提出,然后再合并回去。

  • 分裂流程:

    需要把 \(v\) 中处于 \(x...y\) 的结点分离到 \(u\) 的子树中,当前区间为 \(l...r\)

    \([l,r]\in [x,y]\),把 \(u\) 设为 \(v\),并把 \(v\) 删除。

    否则将 \(u\) 设为新的结点,并将 \(u\) 的左右儿子与 \(v\) 的左右儿子进行分裂。

    记得访问儿子前下放标记,结束后更新自己。

例题

1. CF 1515H Phoenix and Bits

and 操作可以用 xoror 实现,因为这三者分别代表取交,取并,取补集。

然后对整个值域建立 线段树/01 Tire

通过线段树分裂合并提取操作区间。

异或可以用交换左右儿子以及懒标记实现。

或需要将左儿子合并到右儿子处,这个合并的复杂度是均摊的。

额外维护子树内部对于每个二进制位是否存在一个数该位为 \(0\)\(1\)

如果 \(x\) 的为 \(1\) 的每一位子树内均不同时存在数该位为 \(0\)\(1\),则给子树进行异或并退出操作。

然后就可以势能分析了。

线段树相关

原文:https://www.cnblogs.com/iqx37f/p/14883218.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!