当前位置: 首页 > news >正文

线段树思想拆解(下篇)

线段树思想拆解(下篇)

上篇回顾

到这里我们已经处理好了初始化以及添加方法,接下来实现范围的 query 方法

    public int query(int queryL, int queryR) {return query(queryL, queryR, 1, orgLength - 1, 1);}

到此为止通过借助 sum 数组,lazy 数组就已经实现了在范围内统一增加一个数值,查询范围总和的时间复杂度为 O(logN) 了,接下来要引入更新操作,对于更新操作我们需要再借助两个数组来维护更新的懒操作。

接上篇来讲,注意一下我们所有方法的 L 和 R 的范围都是指源数组的范围,即源数组是 8 个数字,则范围为 1-8 , 而对于我们的逻辑线段树数组是通过 index 进行计算得到表示范围的节点数组槽位。

增加 Update 方法

对于 update 方法,思路和 add 方法基本一样,但是如果要同时支持两个方法,需要考虑 update 方法会覆盖之前的 lazyAdd 的缓存任务。

首先提供一个递归调用的 update 方法,然后开放一个简化调用的 update 方法,如下:

private void update(int updateL, int updateR, int operateL, int operateR, int treeIndex, int updateNum) {// 全包直接可以更新if (updateL <= operateL && operateR <= updateR) {lazyUpdate[treeIndex] = updateNum;lazyUpdateFlag[treeIndex] = true;// 直接更新 sumsum[treeIndex] = updateNum * (operateR - operateL + 1);// 清空覆盖懒增加lazyAdd[treeIndex] = 0;return;}// 如果包不住,需要进行下发处理int mid = (operateL + operateR) >> 1;// 懒任务下发pushDownLazyTask(treeIndex, mid - operateL + 1, operateR - mid);if (updateL <= mid) {update(updateL, updateR, operateL, mid, treeIndex << 1, updateNum);}if (updateR > mid) {update(updateL, updateR, mid + 1, operateR, treeIndex << 1 | 1, updateNum);}sum[treeIndex] = sum[treeIndex << 1] + sum[treeIndex << 1 | 1];
}

这里提一下,我在第一次实现的时候,理所应当的思考就和 lazyAdd 一样,提供一个 lazyUpdate[] 数组来阻塞更新的下发就可以了,但是实际实现后是无法通过对数器的,因为无法判断是否有更新,我们无法简单的判断 lazyUpdate[index] != 0 就认定没有更新,有可能就是更新到了 0,所以需要一个标记更新的数组,最后我定义了 lazyUpdateFlag 来辅助判断是否有更新。

所以新增的结构为

private int[] lazyUpdate;
// 单独用一个数组标记是否进行了更新
private boolean[] lazyUpdateFlag;

对于懒任务下发就需要增加处理更新任务下发的逻辑

private void pushDownLazyTask(int index, int leftRange, int rightRange) {// 根据更新标记数组判断是否有懒更新,不然更新 0 的时候没法判断if (lazyUpdateFlag[index]) {int lazyUpdateNum = lazyUpdate[index];lazyUpdate[index] = 0;lazyUpdateFlag[index] = false;int left = index << 1;int right = index << 1 | 1;lazyAdd[left] = 0;lazyAdd[right] = 0;lazyUpdate[left] = lazyUpdateNum;lazyUpdateFlag[left] = true;lazyUpdate[right] = lazyUpdateNum;lazyUpdateFlag[right] = true;sum[left] = leftRange * lazyUpdateNum;sum[right] = rightRange * lazyUpdateNum;}// 这里最后还是会执行一遍懒添加的下发,因为存在先懒更新后再懒添加的情况,这块更新会清空覆盖懒添加,所以不会有先添加后更新的问题if (lazyAdd[index] != 0) {int lazyNum = lazyAdd[index];lazyAdd[index] = 0;lazyAdd[index << 1] += lazyNum;lazyAdd[index << 1 | 1] += lazyNum;sum[index << 1] += leftRange * lazyNum;sum[index << 1 | 1] += rightRange * lazyNum;}
}

这里对于懒更新,因为进行了下发,所以清除更新、添加,计算 sum 数组

最后对数器验证通过

public static void main(String[] args) {//对数器int testTimes = 5000;int addOrUpdateTimes = 5000;int maxAddOrUpdateNum = 5000;int testQueryTimes = 5000;Random random = new Random();//进行测试for (int i = 0; i < testTimes; i++) {int[] origin = RandomUtil.generateArray(30, 10);// System.out.println(Arrays.toString(origin));SegmentTree segmentTree = new SegmentTree(origin);SegmentTreeON segmentTreeON = new SegmentTreeON(origin);int originLength = origin.length;//每次测试进行添加更新操作次数for (int j = 0; j < addOrUpdateTimes; j++) {int num1 = random.nextInt(originLength) + 1;int num2 = random.nextInt(originLength) + 1;int L = Math.min(num1, num2);int R = Math.max(num1, num2);int num = random.nextInt(maxAddOrUpdateNum);if (random.nextInt(10) < 5) {segmentTree.add(L, R, num);segmentTreeON.add(L, R, num);} else {segmentTree.update(L, R, num);segmentTreeON.update(L, R, num);}}for (int k = 0; k < testQueryTimes; k++) {int num1 = random.nextInt(originLength) + 1;int num2 = random.nextInt(originLength) + 1;int L = Math.min(num1, num2);int R = Math.max(num1, num2);if (segmentTree.query(L, R) != segmentTreeON.query(L, R)) {System.out.println("L-R=" + L + "-" + R);System.out.println("segmentTree.query(L,R)=" + segmentTree.query(L, R));System.out.println("segmentTreeON.query(L,R)=" + segmentTreeON.query(L, R));System.out.println("error!!!!! testNum=" + k);return;}}System.out.println("right " + (i + 1));}
}

相关文章:

线段树思想拆解(下篇)

线段树思想拆解&#xff08;下篇&#xff09; 上篇回顾 到这里我们已经处理好了初始化以及添加方法&#xff0c;接下来实现范围的 query 方法 public int query(int queryL, int queryR) {return query(queryL, queryR, 1, orgLength - 1, 1);}到此为止通过借助 sum 数组&…...

Containerd容器镜像管理

1. 轻量级容器管理工具 Containerd 2. Containerd的两种安装方式 3. Containerd容器镜像管理 4. Containerd数据持久化和网络管理 1、Containerd镜像管理 1.1 Containerd容器镜像管理命令 docker使用docker images命令管理镜像单机containerd使用ctr images命令管理镜像,con…...

Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取相机当前数据吞吐量(C#)

Baumer工业相机堡盟工业相机如何通过BGAPISDK里函数来获取相机当前数据吞吐量&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机的数据吞吐量的技术背景CameraExplorer如何查看相机吞吐量信息在BGAPI SDK里通过函数获取相机接口吞吐量 Baumer工业相机通过BGAPI SDK获取…...

Ubuntu服务器版配置wifi

最近把曾经不用的上网本安装了一个Ubuntu-Server版&#xff0c;当成服务器来用&#xff0c;因为家庭网络布线问题&#xff0c;只好用自带的WIFI来连接网络&#xff0c;Server版也没有什么图形化的管理工具&#xff0c;之后手动编辑配置文件了。 Server下面配置起来还是很方便的…...

Windows 主机的VMware 虚拟机访问 wsl-ubuntu 的 API 服务

Windows 主机的VMware 虚拟机访问 wsl-ubuntu 的 API 服务 0. 背景1. 设置2. 删除 0. 背景 需要从Windows 主机的VMware 虚拟机访问 wsl-ubuntu 的 API 服务。 1. 设置 Windows 主机的IP&#xff1a;192.168.31.20 wsl-ubuntu Ubuntu-22.04 的IP&#xff1a;172.29.211.52 &…...

【Spring】(一)Spring设计核心思想

文章目录 一、初识 Spring1.1 什么是 Spring1.2 什么是 容器1.3 什么是 IoC 二、对 IoC 的深入理解2.1 传统程序开发方式存在的问题2.2 控制反转式程序的开发2.3 对比总结 三、对 Spring IoC 的理解四、DI 的概念4.1 什么是 DI4.2 DI 与 IoC的关系 一、初识 Spring 1.1 什么是…...

chrome插件开发实例04-智能收藏夹

目录 功能说明 演示 源码下载 源代码 manifest.json popup.html popup.js background.js 功能说明 基于chrome插件࿰...

iOS技术之 手机系统15.0之后 的 UITableView section header多22像素问题

iOS 15 的 UITableView又新增了一个新属性&#xff1a;sectionHeaderTopPadding 会给每一个section header 增加一个默认高度&#xff0c;当我们 使用 UITableViewStylePlain 初始化 UITableView的时候&#xff0c;就会发现&#xff0c;系统给section header增高了22像素。 解…...

Windows下安装Kafka(图文记录详细步骤)

Windows下安装Kafka Kafka简介一、Kafka安装前提安装Kafka之前&#xff0c;需要安装JDK、Zookeeper、Scala。1.1、JDK安装&#xff08;version&#xff1a;1.8&#xff09;1.1.1、JDK官网下载1.1.2、JDK网盘下载1.1.3、JDK安装 1.2、Zookeeper安装1.2.1、Zookeeper官网下载1.2.…...

linuxARM裸机学习笔记(3)----主频和时钟配置实验

引言&#xff1a;本文主要学习当前linux该如何去配置时钟频率&#xff0c;这也是重中之重。 系统时钟来源&#xff1a; 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源&#xff0c; 24MHz 晶振是 I.MX6U 内核 和其它外设的时钟源 1. 7路PLL时钟源【都是从24MHZ的晶振PLL而来…...

防勒索病毒

随着勒索软件攻击在2023年的激增&#xff0c;网络安全已成为当今最重要的议题之一。根据区块链分析公司Chainaanalysis的最新报告&#xff0c;勒索软件攻击已成为唯一呈增长趋势的基于加密货币的犯罪行为&#xff0c;勒索金额更是比一年前增加了近1.758亿美元&#xff0c;达到4…...

剑指 Offer 53 - II. 0~n-1 中缺失的数字

力扣 一个长度为n-1的递增排序数组中的所有数字都是唯一的&#xff0c;并且每个数字都在范围0&#xff5e;n-1之内。在范围0&#xff5e;n-1内的n个数字中有且只有一个数字不在该数组中&#xff0c;请找出这个数字。 示例 1: 输入: [0,1,3] 输出: 2 示例 2: 输入: [0,1,2,3,4,5…...

vue2和vue3区别

vue2和vue3的区别有以下8点&#xff1a; 1、双向数据绑定原理不同&#xff1b; 2、是否支持碎片&#xff1b; 3、API类型不同&#xff1b; 4、定义数据变量和方法不同&#xff1b; 5、生命周期钩子函数不同&#xff1b; 6、父子传参不同&#xff1b; 7、指令与插槽不同&#x…...

IMV3.0

经历了两个版本&#xff0c;基础内容在前面&#xff0c;可以使用之前的基础环境&#xff1a; v1&#xff1a; https://blog.csdn.net/wtt234/article/details/132139454 v2&#xff1a; https://blog.csdn.net/wtt234/article/details/132144907 一、代码组织结构 二、代码 2.…...

怎么在树莓派环境上搭建web网站,并发布到外网可访问,今天教给大家

怎么在树莓派上搭建web网站&#xff0c;并发布到外网可访问&#xff1f; 文章目录 怎么在树莓派上搭建web网站&#xff0c;并发布到外网可访问&#xff1f;概述使用 Raspberry Pi Imager 安装 Raspberry Pi OS测试 web 站点安装静态样例站点 将web站点发布到公网安装 Cpolarcpo…...

大文件传输软件| 生命科学中的关键因素

在2023年&#xff0c;生命科学领域以及其先进的科学技术吸引了人们的目光。这些研究背后&#xff0c;很少有人知道的是&#xff0c;其中涉及了大量的研究数据需要实时进行文件传输&#xff0c;以便于研究&#xff0c;合作&#xff0c;分享&#xff0c;分析&#xff0c;临床试验…...

varint编码实现原理

简言 1. varint即 variable int&#xff0c;也就是变长整型&#xff0c;在mysql&#xff0c;levelDB&#xff0c;protobuf中都有使用 2. varint编码的优点是对数值较小的数进行编码后占用字节较少&#xff0c;比如[0-127]只占用1个字节&#xff0c;[128~16383]只占用2个字节。…...

如果新电脑是刚安装的mysql,但是旧电脑迁移过来的文件里面有相关的rails文件,运行rake db:migrate一直报错

$ bundle exec rake db:migrate#运行完命令报错 rake aborted! LoadError: libmysqlclient.so.21: cannot open shared object file: No such file or directory - /home/meiyi/.asdf/installs/ruby/2.6.9/lib/ruby/gems/2.6.0/gems/mysql2-0.5.5/lib/mysql2/mysql2.so /home/m…...

ChatGPT已闯入学术界,Elsevier推出AI工具

2022年11月&#xff0c;OpenAI公司发布了ChatGPT&#xff0c;这是迄今为止人工智能在现实世界中最重要的应用之一。 当前&#xff0c;互联网搜索引擎中出现了越来越多的人工智能&#xff08;AI&#xff09;聊天机器人&#xff0c;例如谷歌的Bard和微软的Bing&#xff0c;看起来…...

深度学习论文: RepViT: Revisiting Mobile CNN From ViT Perspective及其PyTorch实现

深度学习论文: RepViT: Revisiting Mobile CNN From ViT Perspective及其PyTorch实现 RepViT: Revisiting Mobile CNN From ViT Perspective PDF: https://arxiv.org/pdf/2307.09283.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://gith…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

高端性能封装正在突破性能壁垒,其芯片集成技术助力人工智能革命。

2024 年&#xff0c;高端封装市场规模为 80 亿美元&#xff0c;预计到 2030 年将超过 280 亿美元&#xff0c;2024-2030 年复合年增长率为 23%。 细分到各个终端市场&#xff0c;最大的高端性能封装市场是“电信和基础设施”&#xff0c;2024 年该市场创造了超过 67% 的收入。…...