ACM线段树的区间合并

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

顺便讲一下如何维护llen和rlen
• llen = lson->llen • rlen = rson->rlen • 还有一种可能的情况 • 可以看到 如果这样的话 一个区间的llen永远不会超过他的左区间 长度 • 事实可能并非如此 如果这个区间的llen == lson->len的话
那么 应该加上什么呢?
• 它可能用来解决的问题比较套路 • 但是可能会配合别的算法进行考虑 • 它是线段树的一个用法
最后再讲一些小东西
• 线段树很重要 也很简单 可以应用在很多地方 • 并且它有很多延伸的版本 • 比如二维线段树 比如函数式线段树/可持久化线段树 • 当然这些都是高级的数据结构 听起来就很厉害 • 当以后大家以后有时间了 并且掌握了线段树的基本使用后 • 可以去学习一下 • 深刻学习 或许最后会得出一些深刻的认识也说不定~
那么 在up函数中 我们如何维护tlen?
• tlen = max(lson->tlen , rson->tlen) 这一点肯定是没有错的 • 如何达到对跨越区间裂缝的len也做考虑呢? • 我们维护一个区间的llen和rlen • 即 紧贴着这个区间左边界和右边界的我们所求串的maxlen • 所以 tlen = max(lson->tlen , rson->tlen , lson->rlen + rson->llen)
这堂课就到这里了
• 风里雨里 • 周末训练赛等你~
但是如果增加新的条件呢?
• 给出 a b 将第a位的值改为b • 刚才的两种解法 都是依靠预处理来达到之后的查询时间 • 如果我们要做更改 就要大量修改预处理出的数据
联想线段树的作用 它刚好可以处理这种问题
• 如果我们能够使用线段树来解决这类区间查询问题(但并不是简单 的带修改求和或者求max) • 我们可以达到询问的O(logn) 和修改的O(logn) • 线段树的建造是O(nlogn)的 查询的总时间也是O(nlogn)的 • 即使不带修改也要比前面的方法优秀
再说一下查询
• 比如我们查询[l , r]的最长连续1 • 我们一开始从[1,N]开始查询 [l,r]必定包含于它 • 首先我们check • 1 r<=mid 我们扔给左子树 • 2 l>=mid+1 扔给右子树 • 3 [l,r]包含区间裂缝
现在就要有三种取舍
• 1 扔给左子树一个查询 [l,mid] • 2 扔给右子树一个查询 [mid+1,r] • 其实这两个查询和前两种没有区别 • 3 穿过这个区间裂缝的子串 我们可以得出来它的l' r' • l' = mid - rlen +1 • r' = mid+ llen • 我们取这个长度在[l,r]中的长度 • 即 min(r,r') - max(l,l') + 1 然后用它更新一下答案
所以 在每一层的query 都会发生这件事情
• 左子树返回一个结果 res1 • 右子树返回一个结果 res2 • 区间裂缝返回一个结果 res3 • 我们找出最大的一个res • 然后把这个res return上去 作为左子树或右子树返回的一个ans • *如果[l,r]和某个子树实在没有关系 res*就是0 • *最底层直接判断
ቤተ መጻሕፍቲ ባይዱ
区间修改如何做 ?
• 鉴于题目类型所限 它如果修改的话 只能对区间进行以下操作 • 1 群体赋值 • 2 群体加和 • 3 进行翻转(0 1 串一类) • 我们肯定要加入延时标记来控制时间复杂度 • 那么 什么时候停止向下呢? • 先停下想一想单点修改的时候怎么做
思维延伸
• 我们更改到单点的最底部 因为只有在地步我们才能直接控制出这 个小区间的l r t • 比如我们直接赋值为0 然后询问连续1的长度 • 那么底部长度为1的区间 我们可以确定 tlen 就是0 • 所以 我们要更新到一个点 这个点的状态可以被完全求出来
解决这类问题 线段树有固定套路
• 这类问题 基本是”带修改的区间查询”连续”问题” • 它可以问你一个区间的LCIS 或者是一个区间的连续某数字 等等
那么我们来看这个解法
• 我们对原有的线段树结构体做一下修改 • 既然是问”最长”那么一个区间肯定要存一下这个区间的最长长度 • 即 tlen • 一个区间的tlen取决于什么呢? • 左区间的tlen 和 右区间的tlen • 还可能 它的tlen跨越这两个区间
• 这个就比较简单了 • if(lson->llen == lson->len) llen = lson->llen + rlen->llen • 同理 rlen也可以这么维护
那么当我们单点修改的时候 就可以这么写
• 我们像往常一样把这个点的修改一直传达到最底部 • 那么这个点的tlen llen rlen 一定为0或者1 (由题意而定) • 然后我们返回的时候写一个up函数 就可以了 • 即 我们不像做修改sum和max的时候那样走到哪一层就更新哪一 层 而是依赖up函数
线段树的区间合并并不止能用来解决01串
• 如果题目要求一个区间的LCIS • 那就记录下来三种len之后 • 每次进行合并的时候check边界的值 来决定是否合并
如果题目带区间翻转怎么办?
• 假如这个问题还是求1的长度 • 那就把0也一样记录下来 • 每次反转 就swap(0,1)
区间合并就这么讲完了
让我们看这个问题
• 给出一个序列 由1和0组成 • 给出一个区间[l,r] • 求这个区间[l,r]中的最长1的串
我们可以使用以下解法
1 区间dp 时间 :时间 O(n^3)的预处理 O(1)的询问 空间 O(n^2) 2 胡乱预处理+探查询问 时间 O(n^2)的预处理 O(n)的询问 空间O(n) 如果询问的量是n 后者比较划算 时间复杂度O(n^2)
所以 其实还是像以前一样更新到区间包裹...
• 如果我们更新[1 , 7] 群体赋值为1 • 我们更新到[3 , 5] 它包含于修改区间 • 我们就可以直接看出来 它的tlen=llen=rlen = 3 • 于是 我们给它加上一个mark=1 代表它曾被群体赋值过1 • 所以 以后down的时候 它的子区间的tlen llenr len 也会被赋值为len
相关文档
最新文档