LastWhisper最后的耳语

动态开点线段树

WKL && YZY·2022-08-15 22:03·974 次阅读

动态开点线段树

动态开点线段树#

为了准备google的面试刷题的时候发现这个知识点其实我一直不太熟悉,所以专门写一篇blog准备一下。

我们将从以下几个方面去讲解:

什么是动态开点线段树#

动态开点线段树是在空间不够时动态的create线段树上的结点,与普通线段树直接build不同,动态开点线段树在使用的过程中动态create

优缺点使用情况#

优点:

  • 元素的值域很大,比如1e9且强制在线(无法离散化)。

缺点:

  • 比正常的线段树复杂一些。

思路讲解及实现#

依据我人脑库中的继承,我的线段树一般有几个基本方法需要实现:

  • push,进行操作往子结点传递信息。
  • pull,进行操作从子结点更新父节点。
  • update(start, end, rt),进行区间更新
  • query(start, end, rt), 进行区间查询
  • build但是这里不需要了

下面解释下tree node

  • ls: left son
  • rs: right son
  • val: 当前node对应的价值
  • lazy:各种懒标记(add, mul)等。

只需要注意的是,动态开点的具体流程,假如ls或者rs为0,则代表对应的节点还没有创建,需要我们动态创建。

思考一下,动态开点应该放在哪个方法里面?

Answer: push方法中,因为我们每次操作前都会调用push往子结点传递信息,如果子结点不存在我们再动态创建。

定义结构体Node

Copy
struct Node{ int ls, rs; // lson, rson int val, add; // val -> value, add -> lazy add Node (int a = 0, int b = 0, int c = 0, int d = 0){ ls = a; rs = b; val = c; add = d; } } tr[MAXN];

定义push,注意我们的宏,主要是为了写的方便,其中len代表区间的长度,因为我们的结构体中没有存区间长度所以我们要传进来。

  • if (!ls(p)) ls(p) = ++ cnt;
  • if (!rs(p)) rs(p) = ++ cnt;

这两行代码就是用于动态的create的。

除此之外还需要注意,如果我们是按这种规则区分的:

  • 左边 [start,mid]|mid=start+end2
  • 右边 [mid+1,end]|mid=start+end2

这样,我们列出公式:

Lenl=end+start2start+1Lenl=endstart+22Lenl=len+12=len-(len/2)Lenr=len12=len/2

于我们的常识有点不符,左边的区间长度为Lenl=len-(len/2)

其他的都和正常的区间线段树类似。注意,这里我们不能使用Lenr=len12,这是因为,虽然左边我们可以直接用len+12,但是这其实有取floor的感觉,不能直接用加减考虑。

Copy
#define ls(x) tr[x].ls #define rs(x) tr[x].rs #define val(x) tr[x].val #define add(x) tr[x].add void push(int p, int len){ // check exists if (!ls(p)) ls(p) = ++ cnt; if (!rs(p)) rs(p) = ++ cnt; if (add(p) == 0) return void(); if (add(p) == -1){ val(ls(p)) = val(rs(p)) = 0; }else if (add(p) == 1){ val(ls(p)) = len - (len / 2); val(rs(p)) = len / 2; } add(ls(p)) = add(p); add(rs(p)) = add(p); add(p) = 0; }

你会发现我们的结构体中并没有存储节点所代表的 leftright ?这是值得思考的问题,这是因为,我们默认 root 节点代表的是 [MIN, MAX],这样我们就可以在 query update 等函数的参数中维护当前节点 p 代表的区间。

TODO#

Example#

LeetCode Range Module#

代码:https://leetcode.cn/submissions/detail/350662555/

需要注意,如果是这种OJ,需要memset结构体或者写到类内。

posted @   Last_Whisper  阅读(976)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示
目录