首页 > 其他分享 >动态开点线段树

动态开点线段树

时间:2022-08-15 22:12:49浏览次数:73  
标签:val rs 线段 len add ls 动态

动态开点线段树

为了准备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

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 = \frac{start + mid}{2}\)
  • 右边 \([mid+1,end] | mid = \frac{start + mid}{2}\)

这样,我们列出公式:

\[\begin{array}{ll} Len_l &=\dfrac{end + start}{2} - start + 1\\ Len_l &=\dfrac{end - start + 2}{2} \\ Len_l &=\dfrac{len + 1}{2} = \verb|len-(len/2)|\\ Len_r &=\dfrac{len - 1}{2} = \verb|len/2| \end{array} \]

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

其他的都和正常的区间线段树类似。

#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;
}

Example

LeetCode Range Module

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

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

标签:val,rs,线段,len,add,ls,动态
From: https://www.cnblogs.com/Last--Whisper/p/16589835.html

相关文章

  • Element cascader动态加载
    一开始也是网上查找:https://blog.csdn.net/lgh1206/article/details/113932595 看的这位博主的,他是自己创建的数据我这边是与后端联调: <el-cascader......
  • 在线动态图连通性
    动态图连通性再这样下去要被自己蠢死维护一副图,支持\(\operatorname{link,cut}\),判断\(x,y\)是否在同一个联通块中最\(naive\)的就是每次双端\(\operatorname{b......
  • C++动态链接库(DLL)文件的创建和调用
    出处:蓟_可爱的叔https://www.cnblogs.com/wjq13752525588/p/16364956.html 一、什么是库    我们在编写C/C++等语言程序的时候,经常会遇到很多反复使用的或者......
  • 线段树
    线段树学习笔记1.线段树简介线段树,是一种二叉搜索树,其每一个节点表示了一段区间。线段树支持的操作有:区间求和或最大/最小值,时间复杂度\(O(logN)\)(p.s.后面代......
  • luoguP3521 [POI2011]ROT-Tree Rotations【线段树】
    你要写热,就不能只写热。要写酷暑,写骄阳,写他人耳闻便生恐的炙烤和炎灼。要写白日出门一刻便肤色黝黑,背心透彻。写求雨心切,写出行伞遮。写夜晚不停的风扇和蝉聒。写鸡......
  • mybatis 10: 动态sql --- part2
    <foreach>标签作用用来进行循环遍历,完成循环条件的查询,批量删除,批量增加,批量更新用法包括循环查询+批量删除+批量增加+批量更新的用法UsersMapper.javap......
  • 注解和反射之动态创建对象执行方法
    点击查看代码packagecom.kuang.reflection;importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;importjava.lang.reflect.InvocationTarget......
  • luoguP3224 [HNOI2012]永无乡【线段树,并查集】
    洞庭青草,近中秋,更无一点风色。玉鉴琼田三万顷,着我扁舟一叶。素月分辉,明河共影,表里俱澄澈。悠然心会,妙处难与君说。应念岭表经年,孤光自照,肝胆皆冰雪。短发萧骚襟袖冷,稳泛......
  • 9.最长公共子序列问题(动态规划)
    题目描述:给定两个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。输入格式:输入数据有多组,每组有两行,每行为一个长度不超过500的字符串(输入全是大......
  • 【学习笔记】线段树优化建图
    先开坑,有时间再说。例题CF786BLegacyCode//线段树优化建图,从寒假一直咕到暑假//之前觉得难得不行,现在看还是挺好理解的#include<queue>#include<cstdio>#includ......