Segment Tree 线段树算法(java)

线段树算法

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

蓄水池算法

蓄水池算法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Learning Enriched Features for Fast Image Restoration and Enhancement 论文阅读笔记

这是2022年TPAMI上发表的大名鼎鼎的MIRNetv2&#xff0c;是一个通用的图像修复和图像质量增强模型&#xff0c;核心是一个多尺度的网络 网络结构整体是残差的递归&#xff0c;不断把残差展开可以看到是一些残差块的堆叠。核心是多尺度的MRB。网络用的损失函数朴实无华&#x…

Vue电商项目--登录与注册

登录注册静态组件 刚刚报了一个错误&#xff0c;找不到图片的资源 assets文件夹--放置全部组件共用静态资源 在样式当中也可以使用符号【src别名】。切记在前面加上 注册业务上 先修改原先的接口成这个按钮 然后把input框里面的数据保存到data中 注册业务下 就是点击获…

1. HTML5的新特性

HTML5的新增特性主要是针对于以前的不足, 增了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题,基本是IE9以上版本的浏览器才支持, 如果不考虑兼容性问题,可以大量使用这些新特性。 1.1 HTML5 新增的语义化标签 ●<header> : 头部标签 ●<nav&…

什么是Heatmap(热图)图表?用DHTMLX可实现快速构建

DHTMLX Chart是DHTMLX最新发布的JavaScript UI小部件库的核心内容之一&#xff0c;这个图表小部件收到了几个重要的更新&#xff0c;但其中最引人注目的是一个新的数据可视化选项——日历热图。 DHTMLX专注于JavaScript和HTML5 UI小部件和库&#xff0c;以帮助开发人员更快地构…

爬虫相关知识与面试题目

常见的反爬虫和应对方法 参考:https://www.cnblogs.com/bsdr/p/5151891.html 0x01 常见的反爬虫 这几天在爬一个网站&#xff0c;网站做了很多反爬虫工作&#xff0c;爬起来有些艰难&#xff0c;花了一些时间才绕过反爬虫。在这里把我写爬虫以来遇到的各种反爬虫策略和应对的…

python selenium.webdriver 爬取政策文件

文章目录 获取文章链接批量爬取政策文件应用selenium爬取文件信息数据处理导出为excel 获取文章链接 获取中央人民政府网站链接&#xff0c;进入国务院政策文件库&#xff0c;分为国务院文件和部门文件&#xff08;发改委、工信部、交通运输部、市场监督局、商务部等&#xff…

uni.app开发小程序如何获取当前经纬度、位置信息以及如何重新发起授权定位

uni.app开发小程序如何获取当前经纬度、位置信息以及如何重新发起授权定位 前提 先去微信小程序后台申请 wx.getLocation接口1.引入下载的高德小程序SDK2.data中定义所需变量3.onLoad中获取实例 并调用获取经纬度 位置方法4.定义获取定位经纬度 位置信息方法5.用户拒绝授权后,可…

架构训练营学习笔记3-5:消息队列备选架构设计实战

本文属于架构训练营学习笔记系列&#xff1a;模块3的案例讲解 总的来说&#xff0c;这篇从更高的维度去讲&#xff0c;而不是关注消息队列的常见问题&#xff1a;比如消息如何发送&#xff0c;消息如何不丢失 &#xff0c;消息如何不重复。总体上分为2部分&#xff1a;利益干系…

数据可视化:揭开数据的视觉奇迹

随着大数据时代的到来&#xff0c;我们面临着海量的数据&#xff0c;如何从中获取有价值的信息成为一项重要的挑战。数据可视化作为一种强大的工具&#xff0c;通过图表、图形和交互界面&#xff0c;将数据转化为可视化的形式&#xff0c;帮助我们更好地理解和分析数据。 数据可…

用OpenCV进行图像分割--进阶篇

1. 引言 大家好&#xff0c;我的图像处理爱好者们&#xff01; 在上一篇幅中&#xff0c;我们简单介绍了图像分割领域中的基础知识&#xff0c;包含基于固定阈值的分割和基于OSTU的分割算法。这一次&#xff0c;我们将通过介绍基于色度的分割来进一步巩固大家的基础知识。 闲…

kafka(一)

一&#xff1a;kafka架构介绍 1. Brokers kafka集群包括一个或者多个服务器&#xff0c;服务器的节点叫做broker。 2. Topic 类似于数据库中的table。物理上不通的topic会分开存储。一个topic的消息会存储在多个broker上。但是在读取的时候&#xff0c;只要选择好topic&…

autok3s k3d rancher研究

参考 功能介绍 | Rancher文档AutoK3s 是用于简化 K3s 集群管理的轻量级工具&#xff0c;您可以使用 AutoK3s 在任何地方运行 K3s 服务。http://docs.rancher.cn/docs/k3s/autok3s/_index 什么是 AutoK3s k3s是经过完全认证的 Kubernetes 产品&#xff0c;在某些情况下可以替…

Docker 容器生命周期:创建、启动、暂停与停止----从创建到停止多角度分析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

vue 限制表情输入

在main.js中加入下列代码 import emoji from ./util/emojiVue.directive(emoji,emoji) 在util文件夹中加入emoji.js 下列代码 const findEle (parent, type) > { return parent.tagName.toLowerCase() type ? parent : parent.querySelector(type)}const emoji {bi…

小程序MobX创建store并实现全局数据共享

查看小程序根目录中是否存在package.json文件 在项目根目录运行cmd 没有package.json文件输入npm init -y初始化一下,初始化一个包管理 安装MobX npm install --save mobx-miniprogram4.13.2 mobx-miniprogram-bindings1.2.1 小程序菜单栏工具–构建npm 根目录创建store文…

Hive概述

Hive 一 Hive基本概念 1 Hive简介 学习目标 - 了解什么是Hive - 了解为什么使用Hive####1.1 什么是 Hive Hive 由 Facebook 实现并开源&#xff0c;是基于 Hadoop 的一个数据仓库工具&#xff0c;可以将结构化的数据映射为一张数据库表&#xff0c;并提供 HQL(Hive SQL)查询…

Dcat-admin使用 Alpine 双向数据绑定

介绍 Alpine.js 这东西真的轻量级&#xff0c;和vue相似&#xff0c;和 livewire 同一个作者&#xff0c;推荐大家使用&#xff0c;可以平替jquery 效果 实现 在 bootstrap.php 引入js Admin::headerJs([https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-y/alpinejs/3.9.0/…

掘金量化—Python SDK文档—4.数据结构

目录 Python SDK文档 4.数据结构 4.1数据类 Tick - Tick 对象 报价quote - (dict 类型) Bar - Bar 对象 L2Order - Level2 逐笔委托 L2Transaction - Level2 逐笔成交 4.2交易类 Account - 账户对象 Order - 委托对象 ExecRpt - 回报对象 Cash - 资金对象 Position - 持仓对象…

Windows操纵kafka

这里写目录标题 启动kafk创建一个测试主题查看所有主题查看first详细信息修改分区数(分区数只能增加 不能减少)删除主题生产者生产数据消费命令 启动kafk 安装目录下 .\bin\windows\kafka-server-start.bat .\config\server.properties创建一个测试主题 安装目录下 .\bin\wi…

从零学习微服务

更新中&#xff0c;关注不断更… 如果觉得需要补充哪些内容&#xff0c;可以在评论区留言或者私信我哦 文章目录 &#x1f31f;引入&#x1f3b6;Feign&#x1f63a;Ribbon&#x1f40e;Naocs&#x1f368;Gateway&#x1f36c;Docker&#x1f6a2;RabbitMQsentinelseata &…