数据结构 - 线段树

1. 预制值:

  • 构建的数组为,nums:【2, 5, 1, 4, 3】
  • 区间和问题,假设求区间 [1,3] 的和

2. 建树

2.1 构建线段树数组

int[] segT = new int[4*n]

(为什么数组大小是4*n???评论区欢迎留言)
在这里插入图片描述

tips:长方格中的left、right,分别代表该节点所求得的区间和。例如,left:0,right:4。代表nums中索引0到4的和=2+5+1+4+3=15。

在这里插入图片描述

  • 核心代码
public void build(int index, int left, int right) {// 2.1.1的工作,递归条件,不可再分区间if (left == right) {segT[index] = nums[left];return;}// 2.1.1的工作,区间多次二分int mid = (right - left) / 2 + left;// 左子树根节点的索引int leftIndex = index * 2;// 右子树根节点的索引int rightIndex= index * 2 + 1;// 构建左、右子树build(leftIndex, left, mid);build(rightIndex, mid+1, right);// 2.1.2的工作,求根节点的和// tips:只有当left==right返回后,才会走这一步segT[index] = segT[leftIndex] + segT[rightIndex];}

3. 更新

逻辑其实和建树一样,在线段树中找到修改节点的对应索引,然后修改其值,然后再依次修改根节点的值即可。
在这里插入图片描述

  • 核心代码
public void update(int index, int start, int end, int updateIndex, int value) {// 找到叶子节点,直接修改值(不可再分区间了)if (start == end) {nums[updateIndex] = value;segT[index] = value;return;} int mid = (start + end) / 2;int leftIndex = index * 2;int rightIndex = index * 2 + 1;// 修改的节点再左子树还是右子树if (updateIndex >= start && updateIndex <= mid) {update(leftIndex, start, mid, updateIndex, value);} else {update(rightIndex, mid + 1, end, updateIndex, value);}segT[index] = segT[leftIndex] + segT[rightIndex];}

4. 查询

查询的逻辑会稍微复杂一点,因为有三个因素:

4.1 查询的范围全落在左子树

在这里插入图片描述

4.2 查询的范围全落在右子树

在这里插入图片描述

4.3 查询的范围既在左子树、又在右子树

在这里插入图片描述

  • 核心代码
public int querySum(int index, int start, int end, int left, int right) {// 查询的索引无效(不是线段树的有意义范围)if (left > end || right < start) {return 0;}// 查询的范围包含该子树的范围,直接返回即可(见下图【包含子树】)else if (left <= start && right >= end) {return st[index].sum;}// 求的左右子树的索引int mid = (start + end) / 2;int leftIndex = index * 2;int rightIndex = index * 2 + 1;// 左、右子树求得的值int leftSum = querySum(leftIndex, start, mid, left, right);int rightSum = querySum(rightIndex, mid + 1, end, left, right);return leftSum + rightSum;}

在这里插入图片描述
图:包含子树

5. 线段树求区间问题模板(最大值、最小值、和)

public class SegmentTree {class Node {int left;int right;int max;int min;int sum;Node() {}Node (int left, int right) {this.left = left;this.right = right;this.max = Integer.MIN_VALUE;this.min = Integer.MAX_VALUE;this.sum = 0;}}int n;Node[] st;int[] nums;public void build(int index, int left, int right) {if (left == right) {st[index].sum = nums[left];st[index].max = nums[left];st[index].min = nums[left];return;}int mid = (right - left) / 2 + left;int leftIndex = index * 2;int rightIndex= index * 2 + 1;build(leftIndex, left, mid);build(rightIndex, mid+1, right);st[index].max = Math.max(st[leftIndex].max, st[rightIndex].max);st[index].min = Math.min(st[leftIndex].min, st[rightIndex].min);st[index].sum = st[leftIndex].sum + st[rightIndex].sum;}public void init(int N, int[] arr) {n = N;st = new Node[4 * n + 1];for (int i = 1; i <= 4 * n; i++) {st[i] = new Node();}nums = arr;}public int querySum(int left, int right) {return querySum(1, 0, n-1, left, right);}public int querySum(int index, int start, int end, int left, int right) {if (left > end || right < start) {return 0;} else if (left <= start && right >= end) {return st[index].sum;}int mid = (start + end) / 2;int leftIndex = index * 2;int rightIndex = index * 2 + 1;int leftSum = querySum(leftIndex, start, mid, left, right);int rightSum = querySum(rightIndex, mid + 1, end, left, right);return leftSum + rightSum;}public int queryMax(int left, int right) {return queryMax(1, 0, n-1, left, right);}public int queryMax(int index, int start, int end, int left, int right) {if (left > end || right < start) {return 0;} else if (left <= start && right >= end) {return st[index].sum;}int mid = (start + end) / 2;int leftIndex = index * 2;int rightIndex = index * 2 + 1;int leftMax = queryMax(leftIndex, start, mid, left, right);int rightMax = queryMax(rightIndex, mid + 1, end, left, right);return Math.max(leftMax, rightMax);}public int queryMin(int left, int right) {return queryMin(1, 0, n-1, left, right);}public int queryMin(int index, int start, int end, int left, int right) {if (left > end || right < start) {return Integer.MAX_VALUE;} else if (left <= start && right >= end) {return st[index].sum;}int mid = (start + end) / 2;int leftIndex = index * 2;int rightIndex = index * 2 + 1;int leftMin = queryMin(leftIndex, start, mid, left, right);int rightMin = queryMin(rightIndex, mid + 1, end, left, right);return Math.min(leftMin, rightMin);}public void update(int index, int start, int end, int updateIndex, int value) {if (start == end) {nums[updateIndex] = value;st[index].sum = value;st[index].max = value;st[index].min = value;return;} int mid = (start + end) / 2;int leftIndex = index * 2;int rightIndex = index * 2 + 1;if (updateIndex >= start && updateIndex <= mid) {update(leftIndex, start, mid, updateIndex, value);} else {update(rightIndex, mid + 1, end, updateIndex, value);}st[index].max = Math.max(st[leftIndex].max, st[index].max);st[index].min = Math.min(st[leftIndex].min, st[index].min);st[index].sum = st[leftIndex].sum + st[index].sum;}public void update(int index, int value) {nums[index] = value;update(1, 0, n - 1, index, value);}}

6. 例题

leetcode307 区域和检索 - 数组可修改

7. 注意

并不是所有求区间和都能用线段树,例如leetcode327 区间和的个数,元素的值范围是 -231<=num<= 231-1,如果直接构建线段树,空间复杂度会挤爆!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/674075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

红队打靶练习:PHOTOGRAPHER: 1

目录 信息收集 1、arp 2、nmap 3、nikto 目录扫描 1、gobuster 2、dirsearch WEB 信息收集 enum4linux smbclient 8000端口 CMS利用 信息收集 文件上传漏洞利用 提权 信息收集 get user.txt get flag 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# a…

Codeforces Round 923 (Div. 3)

Codeforces Round 923 (Div. 3) Codeforces Round 923 (Div. 3) A. Make it White 题意&#xff1a;略 思路&#xff1a;找最小和最大的‘B’下标即可 AC code&#xff1a; void solve() {cin >>n;string s; cin>> s;int mn INF, mx 0;for (int i 0; i <…

Linux文件和目录管理

目录基础 Linux操作系统以目录的方式来组织和管理系统中的所有文件。所谓的目录&#xff0c;就是将所有文件的说明信息采用树状结构组织起来。每个目录节点之下会有文件和子目录。 所有一切都从 ‘根’ 开始&#xff0c;用 ‘/’ 代表, 并且延伸到子目录。 bin&#xff1a;B…

ongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(2)-Swagger框架集成

Swagger是什么&#xff1f; Swagger是一个规范且完整API文档管理框架&#xff0c;可以用于生成、描述和调用可视化的RESTful风格的 Web 服务。Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口&#xff0c;可以让人和计算机拥有无须访问源码、文档或网络流量监测就…

Java并发基础:Deque接口和Queue接口的区别?

核心概念 Deque&#xff08;double ended queue&#xff0c;双端队列&#xff09;和Queue&#xff08;队列&#xff09;都是Java集合框架中的接口&#xff0c;它们用于处理元素的排队和出队&#xff0c;但是它们之间存在一些重要的区别&#xff0c;如下&#xff1a; 1、Queue…

HarmonyOS 创建components目录 定义全局自定义组件导出供整个项目使用

之前我的文章 harmonyOS 自定义组件基础演示讲解 我们讲解了 自定义组件的基础用法 但是 我们是写在单个page文件中的 这样 我们跨文件使用就很不友好了 如下图 指向 ets目录下 创建一个目录 按我们 前端开发以往的习惯 这个目录要叫 components 专门放组件集合的地方 然后 按…

《MySQL 简易速速上手小册》第3章:性能优化策略(2024 最新版)

文章目录 3.1 查询优化技巧3.1.1 基础知识3.1.2 重点案例3.1.3 拓展案例 3.2 索引和查询性能3.2.1 基础知识3.2.2 重点案例3.2.3 拓展案例 3.3 优化数据库结构和存储引擎3.3.1 基础知识3.3.2 重点案例3.3.3 拓展案例 3.1 查询优化技巧 让我们来聊聊如何让你的 MySQL 查询跑得像…

3.3-媒资管理之MinIo分布式文件系统上传视频

文章目录 媒资管理5 上传视频5.1 需求分析5.2 断点续传技术5.2.1 什么是断点续传5.2.2 分块与合并测试5.2.3 视频上传流程5.2.4 minio合并文件测试 5.3 接口定义5.4 上传分块开发5.4.1 DAO开发5.4.2 Service开发5.4.2.1 检查文件和分块5.4.2.2 上传分块5.4.2.3 上传分块测试 5.…

高并发对于服务器性能有什么要求?

随着互联网的普及和应用程序的复杂度增加&#xff0c;高并发已经成为许多应用程序必须面对的问题。高并发是指在短时间内有大量用户同时访问应用程序或数据库&#xff0c;对服务器性能提出了更高的要求。本文将探讨高并发对于服务器性能的要求。 一、高并发对服务器硬件的要求…

【Fabric.js】监听画布or元素的点击、选中、移动、添加、删除销毁、变形等各事件

在fabric使用过程中&#xff0c;如果想要玩各种花样&#xff0c;那么fabric的事件监听是一定、必须、肯定要掌握&#xff01;&#xff01;&#xff01; 例子就用vue项目组件里的代码&#xff0c;fabric的使用跟vue、react、angular之类的框架都没任何关系&#xff01; 并且本de…

第205篇| 送给新年12条格言,一些有用的废话

这是2024年一月份flomo和notion 上聚合的系列文章 (01)&#xff1b; 具体方法用的是这个 &#xff1a; 【知识沙虫&#xff0c;一个简单易用的知识体系建模工具】https://mp.weixin.qq.com/s/V2Cdq-1PbMQYvpE4o9NLpQ 首先&#xff0c;方法用下来还是很给力的。输出很快。不过前…

SERVLET过滤器

SERVLET过滤器 全球因特网用户使用不同类型的Web浏览器访问应用服务器上存储的Web应用程序。每个浏览器根据对应的Web浏览器窗口中的设置显示应用程序中的信息。Web应用程序可能会有一些客户机的Web浏览器不支持的HTML标记或功能。这种情况下,应用程序在客户机的Web浏览器中可…

MIMIC-IV官方视图解析 - AKI 肌酐 (kdigo_creatinine、kdigo_stages)

判断AKI我们可以通过肌酐和尿量两个指标来看&#xff0c; 今天我们主要提取肌酐。 kidgo指南的表格 AKI诊断标准&#xff1a;符合以下情况之一者即可被诊断为AKI&#xff1a;①48小时内Scr升高超过26.5μmol/L(0.3mg/dl)&#xff1b;②Scr升高超过基线1.5倍——确认或推测为7…

利用Intersection Observer实现图片懒加载性能优化

ntersection Observer是浏览器所提供的一个 Javascript API&#xff0c;用于异步的检测目标元素以及祖先或者是顶级的文档视窗的交叉状态 这句话的意思就是&#xff1a; 我们可以看的图片当中&#xff0c;绿色的 target element&#xff08;目标元素&#xff09;&#xff0c;…

删除和清空Hive外部表数据

外部表和内部表区别 未被external修饰的是内部表&#xff08;managed table&#xff09;&#xff0c;被external修饰的为外部表&#xff08;external table&#xff09;&#xff1b; 区别&#xff1a; 内部表数据由Hive自身管理&#xff0c;外部表数据由HDFS管理&#xff1b; …

SpringBoot和SpringMVC

目录 一、springboot项目 &#xff08;1&#xff09;创建springboot项目 &#xff08;2&#xff09;目录介绍 &#xff08;3&#xff09;项目启动 &#xff08;4&#xff09;运行一个程序 &#xff08;5&#xff09;通过其他方式创建和运行springboot项目 二、SpringMVC…

高可用 k8s 1.29 一键安装脚本, 丝滑至极

博客原文 文章目录 集群配置配置清单集群规划集群网络规划 环境初始化主机配置 配置高可用ApiServer安装 nginx安装 Keepalived 安装脚本需要魔法的脚本不需要魔法的脚本配置自动补全加入其余节点 验证集群 集群配置 配置清单 OS&#xff1a; ubuntu 20.04kubernetes&#xf…

【Scala】1. 变量和数据类型

1. 变量和数据类型 1.1 for begining —— hello world 新建hello.scala文件&#xff0c;注意object名字与文件名一致。 object hello { def main(args:Array[String]): Unit { println("hello world!") } }运行后打印结果如下&#xff1a; hello world!Pr…

【射影几何13 】梅氏定理和塞瓦定理探讨

梅氏定理和塞瓦定理 目录 一、说明二、梅涅劳斯&#xff08;Menelaus&#xff09;定理三、塞瓦(Giovanni Ceva&#xff09;定理四、塞瓦点的推广4.1 共线定理4.2 三角形外的塞瓦点 一、说明 在射影几何中&#xff0c;梅涅劳斯&#xff08;Menelaus&#xff09;定理和塞瓦定理是…

最大子数组和[中等]

一、题目 给定一个长度为n的环形整数数组nums&#xff0c;返回nums的非空 子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开头相连呈环状。形式上&#xff0c;nums[i]的下一个元素是nums[(i 1) % n]&#xff0c;nums[i]的前一个元素是nums[(i - 1 n) % n]。 子数…