Segment Tree 线段树算法(java)

news2024/11/25 0:31:17

线段树算法

  • Segment Tree 线段树算法
    • 代码演示
  • 蓄水池算法

Segment Tree 线段树算法

什么是线段树算法:
线段树(Segment Tree)是一种基于树结构的数据结构,用于解决区间查询问题,例如区间最大值、最小值、区间和等。线段树是一种高度平衡的二叉树,每个节点都代表了一个区间。下面我们来详细了解一下线段树算法。

线段树的构建
线段树的构建过程可以通过递归的方式实现。对于一个给定的数组,我们首先构建一个高度为 log n 的线段树,其中 n 是数组的长度。每个节点都代表了一个区间,例如左儿子节点代表[l, r],右儿子节点代表[r+1, r2]。具体的构建过程如下:
1.初始化根节点,区间为[0, n-1]。
2.对于每个节点,如果它的左右儿子节点存在,就递归构建左右儿子节点。
3.每个节点的值根据需要更新,例如查询最大值时,每个节点存储的值应该是该区间内的最大值
4.当构建到叶子节点时,将叶子节点的值存储为对应区间的值。

线段树查询
线段树查询可以通过递归的方式实现。对于一个查询区间[l, r],我们从根节点开始,根据区间与节点所代表区间的关系,逐步向下遍历子树,直到到达叶子节点。在遍历过程中,我们可以根据需要更新节点的值,例如查询最大值时,如果当前节点的值比查询区间的值更大,就将当前节点的值更新为查询区间的值。具体的查询过程如下:
1.从根节点开始,如果当前节点所代表的区间与查询区间有交集,就继续向下遍历。
2.如果当前节点的左儿子节点存在,并且左儿子节点所代表的区间与查询区间有交集,就递归查询左儿子节点。
3.如果当前节点的右

示例1:
在这里插入图片描述 线段树是一种二叉搜索树。他将一段区间划分为若干个单位区间,每个节点之间存储一个区间。思想类似于分治思想。

如图所示,线段树中每一个节点都存储着区间[1,10]中的信息,叶子节点的L = R。大致思想为:将大区间平分为2个小区间,每一个小区间再平分为更小的2个区间,以此类推直到每个区间的L = R,通过对这些区间的修改和查询来实现对大区间的修改和查询。
单点查找、修改的时间复杂度:O(log2n)
线段树维护的问题必须满足区间加法 例如:[1,3] + [2,4] = [1,4]。

代码演示

 public static class SegmentTree{
        //记录原数组的长度, 线段树下标是从1 开始,原数组是从0开始,
        private int MAXN;
        //保存原数组的信息,不过下标从1开始了
        private int[]arr;
        //模拟线段树维护记录区间和
        private int[]sum;
        //为累加和懒加载
        private int[]lazy;
        //区间更新的值
        private int[]change;
        //是否更新的标记
        private boolean[]update;

        public SegmentTree(int[] origin) {
            MAXN = origin.length + 1;
            for (int i = 1; i < MAXN;i++){
                arr[i] = origin[i - 1];
            }
            //用来记录逻辑概念中,某一范围的累加和信息。
            sum = new int[MAXN << 2];
            //用来支持逻辑概念中,某一个范围沒有往下透传的累加任务
            lazy = new int[MAXN << 2];
            //用来支持逻辑概念中,某一个范围更新任务,更新成了什么
            change = new int[MAXN << 2];
            // 用来支持逻辑概念中,某一个范围有没有更新操作的任务
            update = new boolean[MAXN << 2];
        }

        /**
         * rt 代表逻辑概念中 所在的位置
         * @param rt
         */
        public void pushUp(int rt){
            sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
        }

        /**
         * 初始化线段树
         * 初始化时 先把sum数组填好
         * @param l
         * @param r
         * @param rt
         */
        public void build(int l,int r,int rt){
            if (l == r){
                sum[rt] = arr[l];
                return;
            }
            int mid = (r + l) >> 1;
            build(l,mid,rt << 1);
            build(mid + 1,r,rt << 1 | 1);
            pushUp(rt);
        }
        /**
         * 任务往下分配
         * @param rt 当前位置
         * @param ln 分配任务的左边界
         * @param rn 分配任务的右边界
         */
        private void pushDown(int rt,int ln,int rn){
            if (update[rt]){
                update[rt << 1] = true;
                update[rt << 1 | 1] = true;
                change[rt << 1] = change[rt];
                change[rt << 1 | 1] = change[rt];
                lazy[rt << 1] = 0;
                lazy[rt << 1 | 1] = 0;
                sum[rt << 1] = change[rt] * ln;
                sum[rt << 1 | 1] = change[rt] * rn;
                update[rt] = false;
            }
            //懒加载的数据分发下去
            if (lazy[rt] != 0){
                lazy[rt << 1] += lazy[rt];
                sum[rt << 1] += lazy[rt] * ln;
                lazy[rt << 1 | 1] += lazy[rt];
                sum[rt << 1 | 1] += lazy[rt] * rn;
                lazy[rt] = 0;
            }
        }

        /**
         * L - R 任务的范围,C 修改的大小
         * l r ,rt 所负责的范围。
         * @param L
         * @param R
         * @param C
         * @param l
         * @param r
         * @param rt
         */
        public void add(int L,int R,int C,int l,int r,int rt){
            if (L <= l && r <= R){
                sum[rt] += C * (r - l + 1);
                lazy[rt] += C;
                return;
            }
            int mid = (r + l) >> 1;
            //任务没有全包,就下发。
            pushDown(rt,mid - l + 1,r - mid);
            if (L <= mid){
                add(L,R,C,l,mid,rt << 1);
            }
            if (R > mid){
                add(L,R,C,mid + 1,r,rt << 1 | 1);
            }
            pushUp(rt);
        }
       

        /**
         *  //L - R 范围内所有值都变成 C
         *  //l - r 是 rt 所在位置的包含数字的范围
         * @param L
         * @param R
         * @param C
         * @param l
         * @param r
         * @param rt
         */
        public void update(int L,int R,int C,int l,int r,int rt){
            //所在范围被全包了。
            if (L <= l && r <= R){
                change[rt] = C;
                update[rt] = true;
                sum[rt] = (r - l + 1) * C;
                lazy[rt] = 0;
                return ;
            }

            int mid = (r + l) >> 1;
            pushDown(rt,mid - l + 1,r - mid);
            if (L <= mid){
                update(L,R,C,l,mid ,rt << 1);
            }
            if (R > mid){
                update(L,R,C,mid + 1,r,rt << 1 | 1);
            }
            pushUp(rt);
        }

       

        /**
         * 查询
         *  //L - R 要查询的范围
         *   //l - r 是 rt 所包含的范围。
         * @param L
         * @param R
         * @param l
         * @param r
         * @param rt
         * @return
         */
        public long query(int L,int R,int l,int r,int rt){
            if (L <= l && r <= R){
                return sum[rt];
            }
            int mid = (r + l) >> 1;
            pushDown(rt,mid - l + 1,r - mid);
            long ans = 0;
            if (L <= mid){
                ans += query(L,R,l,mid,rt << 1);
            }
            if (R > mid){
                ans += query(L,R,mid + 1, r, rt << 1 | 1);
            }
            return ans;
        }
    }

蓄水池算法

蓄水池算法

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

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

相关文章

【数据结构】图解八大排序(下)

文章目录 一、前言二、快速排序1. hoare 版2. 挖坑法3. 前后指针法4. 快排的非递归实现5. 时空复杂度分析 三、归并排序1. 递归实现2. 非递归实现 四、计数排序 一、前言 在上一篇文章中&#xff0c;我们已经学习了五种排序算法&#xff0c;还没看过的小伙伴可以去看一下&…

C语言 —— 浮点类型详解及 IEEE754 规定

【C语言趣味教程】(3) 浮点类型&#xff1a;单精度浮点数 | 双精度浮点型 | IEEE754 标准 &#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; ​—— 热门专栏《维生素C语言》的重制版 —— &#x1f4ad; 写在前面&#xff1a;这是…

Paragon NTFS2023中文最新版mac读写NTFS移动硬盘

当我们使用macOS系统将数据拷贝或写入NTFS格式磁盘时&#xff0c;却发现不能操作成功。搜索原因或解决方案时&#xff0c;许多网友推荐安装磁盘管理软件——Paragon NTFS for Mac。 往往大家都会有两个疑问&#xff0c;一是为什么非要使用NTFS格式的磁盘&#xff1f;二是为什么…

C/C++程序内存区域划分以及各区域的介绍

C/C程序内存区域划分 直接上图&#xff1a; 在这里插入图片描述 注&#xff1a;以下的说明均已VS2019为例 栈区&#xff08;stack&#xff09; 在执行函数时&#xff0c;函数内局部变量的存储单元都可以在栈上创建&#xff0c;函数执行结束时这些存储单元会自动释放。栈内…

用自己的数据拟合Sigmoid函数(Matlab平台)

%% 拟合sigmoid曲线 sigmoid (params, x) params(1) ./ (1 exp(-params(2) .* (x - params(3)))) params(4); %params(1) 是斜率参数&#xff0c;params(2) 是增长速率参数&#xff0c;params(3) 是 x 值的偏移参数&#xff0c;params(4) 是 y 值的偏移参数。 initialGuess…

剑指offer刷题笔记--Num51-60

1--数组中的逆序对&#xff08;51&#xff09; 主要思路&#xff1a; 基于归并排序&#xff0c;视频讲解参考&#xff1a;数组中的逆序对 #include <iostream> #include <vector>class Solution { public:int reversePairs(std::vector<int>& nums) {if(…

【力扣算法17】之 19. 删除链表的倒数第 N 个结点 python

文章目录 问题描述示例1示例2示例3提示 思路分析代码分析完整代码详细分析运行效果截图完结 问题描述 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例1 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例2…

加强安全防护,提升日志管理——探索EventLog Analyzer

导言&#xff1a; 在当今数字化时代&#xff0c;安全威胁和数据泄露已经成为各个组织和企业面临的严峻挑战。有效的日志管理和监控是确保网络安全的重要一环。本文将介绍EventLog Analyzer&#xff08;事件日志分析器&#xff09;这一强大工具&#xff0c;探索其在日志安全方面…

五、DQL-2.基本查询

一、数据准备 1、删除表employee&#xff1a; drop table employee; 2、创建表emp&#xff1a; 3、添加数据&#xff1a; 4、查看表数据&#xff1a; 【代码】 -- 查询数据--------------------------------------------------------- drop table emp;-- 数据准备-----------…

uni-app image加载错误 404 替换为默认图片

双层v-for 使用item修改 aitem.cat_icon || defaultPic绑定图片src属性为aitem.cat_icon 如果aitem.cat_icon的值为空字符串或undefined&#xff0c;那么默认图片defaultPic被显示出来当图片加载错误时,触发handleImageError方法,将aitem传进去 <!-- 页面--><view …

windows下mysql8定时备份,bat脚本编写,dos免密执行

前提&#xff1a;mysql8已经安装。 编写脚本copy_mysql_data.bat echo off set timestamp%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2% set backupfileD:\ProgramData\MySQL\Backup\backup_%timestamp%.sql set mysqlpathD:\Program Files\MySQL\MyS…

成为一个年薪30W+的DFT工程师是一种什么体验?

一直以来&#xff0c;DFT都是数字IC设计行业中相对神秘的一个岗位。 你说他重要吧&#xff0c;并不是所有芯片设计公司都有这个岗位&#xff0c;你说他不重要吧&#xff0c;但凡芯片产品达到一定规模后&#xff0c;就必须设置DFT部门。 一、什么是DFT&#xff1f; DFT&#x…

1haclon 简单操作

文章目录 *读取图片 read_image(Image,claudia) *转换为灰度 rgb1_to_gray(Image,GrayImage)阈值分割 区域连接 获取最衣服 *读取图片 read_image(Image,claudia) *转换为灰度 select_shape (Connection, SelectedRegions, area, and, 40963.3, 44724.8) rgb1_to_gray(Image,Gr…

AI绘画 | 迷人武士美少女战士作品集

今天用Midjourney生成了质量极高的美少女武士后续会作为固定栏目来分享美图接下来请欣赏作品 提示词分享&#xff1a;1.an asian girl dressed in samurai style, in the style of anime aesthetic, trick of the eye paintings, dollcore, light red and black, resin, 8k, ex…

教程 | 如何10秒内一键生成高质量PPT

Hi! 大家好&#xff0c;我是赤辰&#xff01; 近期新进的学员不少职场小白&#xff0c;对AI工具提效办公很感兴趣&#xff0c;今天火速给大家安排&#xff0c;ChatGPTMindShow强强联合&#xff0c;30秒内快速生成PPT&#xff0c;对于策划小白来说简直是福音呀&#xff01; 市…

Java 多文件压缩与解压

1&#xff0c;写多个文件到压缩包 import org.apache.tools.zip.ZipEntry;import org.apache.tools.zip.ZipFile;import org.apache.tools.zip.ZipOutputStream;public static void main(String[] args) {//压缩文件对象String zipPath "D:\\download\\files0719.zip&quo…

15 大模型训练 内存优化

先看GPU结构&#xff0c;我们常说显存的时候&#xff0c;说的一般就是Global memory 训练的过程中&#xff0c;我们为了反向传播过程&#xff0c;必须将中间的结果&#xff08;激活值&#xff09;存储下来。 在训练的过程中&#xff0c;那些会消耗内存呢&#xff1f; model we…

ubuntu20.04系统安装使用labelme标注数据集

一、Anaconda的安装 请参考&#xff1a;MediapipeVSCodeAnaconda 实时检测手部关键点并保存视频_苦瓜汤补钙的博客-CSDN博客 二、Labelme的安装 1.打开终端创建虚拟环境 # 创建labelme的环境 conda create -n labelme python3.9 输入“y”&#xff0c;然后回车。 2.激活虚拟…

为什么媒体和创意工作者更喜欢 Splashtop 进行远程访问

在当今快速发展的数字环境中&#xff0c;可靠的远程访问已成为全球媒体和创意工作者不可或缺的工具。 远程访问让创意工作者不再受传统办公空间边界的限制&#xff0c;完全实现了随时随地办公。无论是实时剪辑、高分辨率渲染还是其他创意任务&#xff0c;创意工作者对高性能远…

Go语言之包管理

1、package Go语言是使用包来组织源代码的&#xff0c;包&#xff08;package&#xff09;是多个 Go 源码的集合&#xff0c;是一种高级的代码复用方案。Go语言中为我们提供了很多内置包&#xff0c;如 fmt、os、io 等。任何源代码文件必须属于某个包&#xff0c;同时源码文件的…