数据结构 - 线段树

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,一经查实,立即删除!

相关文章

代码随想录算法训练营第五十八天 | 739. 每日温度、496. 下一个更大元素 I

739. 每日温度 题目链接&#xff1a;739. 每日温度 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0…

红队打靶练习: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…

Flink大状态和Checkpoint调优

文章迁移&#xff0c;待整理 2. 状态和Checkpoint调优 2.1 大状态调优 我们生产大多数会使用 fsState &#xff0c;memState程序挂了状态就丢了&#xff0c;应该没人会在生产使用&#xff0c;但是涉及到一些大状态&#xff0c;fsState效率很低&#xff0c;这时候会选择 roc…

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

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

Linux: VM: hang 的一种情况

https://lore.kernel.org/lkml/2023082606-viper-accuracy-b0fdgregkh/T/ https://bugs.almalinux.org/view.php?id445 这里提到一个情况&#xff0c;会导致guest层VMhang住&#xff1b;算是不同类型数据的比较导致的一个问题。 影响的版本是&#xff1a; Install Almalinux …

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;对服务器性能提出了更高的要求。本文将探讨高并发对于服务器性能的要求。 一、高并发对服务器硬件的要求…

Javascript第十二个知识点:Dom

Dom --> document object model 文档对象模型 我们编写的HTML代码中&#xff0c;有许多标签&#xff0c;body、h1、p、div……都可以成为节点。 我们操控dom节点就是使用javascript去操控html里的每一个标签 那么我们该怎么操作dom节点呢&#xff1f; 获取dom节点 首先…

HDFS架构 之 元数据架构解析

1、内存Tree介绍啊 1.1 namenode启动流程 1.1.1 启动流程 1、加载fsimage文件 FsImage是一种持久化到磁盘上的文件,里面包含了集群大部分的meta数据,持久化的目的主要是为了防止meta数据丢失,也就是在HDFS不可用的情况下还能够保证绝大多数的数据是正常的。这个工作在Nam…

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

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

极智芯 | 解读国产CPU系列汇总

欢迎关注我的公众号「极智视界」,获取我的更多技术分享 大家好,我是极智视界,本文分享一下 解读国产CPU系列汇总。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码和资源下载,链接:https://t.zsxq.com/0aiNxERDq 最近执笔输出了一些 "解读国产 …

第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…