【数据结构】线段树

news2024/9/21 10:46:57

算法提高课笔记 还未更新完

文章目录

  • 原理
  • pushup
  • build
  • modify
  • query
  • pushdown(懒标记 / 延迟标记)
  • 扫描线法

原理

时间复杂度:O(logn)

线段树是一棵二叉树,把一段区间分成多个部分
在这里插入图片描述
类似堆的方式,用一维数组存整棵树

对于编号x的结点:

  • 父结点 ⌊ x ⌋ \lfloor x \rfloor x,表示为 x >> 1
  • 左子树 2 x 2x 2x,表示为 x << 1
  • 右子树 2 x + 1 2x+1 2x+1,表示为 x << 1 | 1

对于长度为n的区间,最坏估计有 4 n − 1 4n-1 4n1 个结点,因此 开数组时空间一般开 4 n 4n 4n

pushup

由子结点计算父结点的信息

模板:

// u表示当前树中结点编号 lr表示树中结点左右子结点
void pushup(Node &u, Node &l, Node &r)
{
    /* 此处用[l]和[r]的值更新[u] */
}

void pushup(int u)
{
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

build

将一段区间初始化为线段树

  1. 首先记录下当前区间的左右端点,如果左端点和右端点相等就直接返回
  2. 如果不相等,取中间值 mid,然后分别递归左右两段

模板:

// u表示当前树中结点编号 lr表示区间左右端点
void build(int u, int l, int r)
{
    if (l == r) // 左右端点相同表示到达叶子结点
    {
        tr[u] = {    }; // 创建该结点
    }
    else
    {
        tr[u].l = l, tr[u].r = r;
        int mid = l + r >> 1; // 取中间值
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); // 分别构造左右两棵子树
        pushup(u); // 利用pushup更新该点
    }
}

modify

修改单点或区间(需要用到push_down操作)

修改单点模板:

// u为当前树中结点编号 要把x位置的值更新为v
void modify(int u, int x, int v)
{
    if (tr[u].l == x && tr[u].r == x) // 到达叶子结点 直接更新
    {
        tr[u] = {     };
    }
    else
    {
        int mid = tr[u].l + tr[u].r >> 1; // 取中间值
        if (x <= mid) modify(u << 1, x, v); // 要更新的位置在左半部分
        else modify(u << 1 | 1, x, v); // 要更新的位置在右半部分
        pushup(u); // 更新此位置结点
    }
}

修改区间模板:

void modify(int u, int l, int r, int d)
{
    if (tr[u].l >= l && tr[u].r <= r) // 当前树中结点在所求区间之内
    {
        tr[u].sum += (i64)(tr[u].r - tr[u].l + 1) * d; // 更新区间信息
        tr[u].add += d; // 打上懒标记
    }
    else // 当前树中结点不在所求区间之内
    {
        pushdown(u); // 将懒标记向下传递
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r, d); // 与左半段有重合部分就更新左半段
        if (r > mid) modify(u << 1 | 1, l, r, d); // 与左半段有重合部分就更新左半段
        pushup(u); // 由于modify修改了区间结点的信息,所以被修改的结点的祖先结点都需要重算一遍
    }
}

query

查询区间信息

假设我们要查询某区间的最大值

定义 [l, r] 为我们要查询的区间,[Tl, Tr] 为树中结点(当前我们正在维护的区间),这两个区间会有如下两种关系:

  • [ T l , T r ] ⊂ [ l , r ] [Tl, Tr]\subset[l, r] [Tl,Tr][l,r],树中结点完全包含在要查询的区间内部
    这种情况直接返回当前区间最大值即可
  • [ l , r ] ⋂ [ T l , T r ] ≠ ∅ [l, r]\bigcap[Tl, Tr]\not=\emptyset [l,r][Tl,Tr]=,二者有交集
    和左边有交集就递归到左边做一遍,和右边有交集就递归到右边做一遍
    l > mid只递归右边,r <= mid只递归左边,否则左右都递归

模板:

Node query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r) return tr[u]; // 当前区间在被查询区间之内 直接返回
    else
    {
        int mid = tr[u].l + tr[u].r >> 1; // 取中间值
        if (r <= mid) return query(u << 1, l, r); // 被查询区间在当前区间左半部分
        else if (l > mid) return query(u << 1 | 1, l, r); // 被查询区间在当前区间右半部分
        else // 被查询区间横跨当前区间的左右两部分
        {
            auto left = query(u << 1, l, r); // 计算出左半部分值
            auto right = query(u << 1 | 1, l, r); // 计算出右半部分值
            Node res;
            pushup(res, left, right); // 更新结果
            return res;
        }
    }
}

pushdown(懒标记 / 延迟标记)

将父结点的修改更新到子结点

单点修改可以只用pushup,涉及到区间修改就需要使用pushdown

懒标记 :在当前树中结点上打上懒标记,就表示对以当前树中结点为根结点每一个子树都进行操作(根结点自己不用操作)

那么懒标记怎么进行传递呢?

焗个栗子:比如我们在蓝色的这一段区间上打上懒标记
在这里插入图片描述
每当我们需要遍历蓝色区间结点下方的子结点时,我们就把懒标记传递给下一层结点,同时把根结点的懒标记删除,就像这样:
在这里插入图片描述
当然,除了传递标记,我们还需要对线段树中记录的值进行更新,比如说这个线段树记录的是区间和,打上懒标记表示这一段区间每一个数都要加上a,那么我们在传递懒标记的同时,还需要让下方结点的区间和加上(r - l + 1) * a,其中(l - r + 1)表示下方被更新结点的区间长度

以此类推,每当我们需要遍历下方结点时,就把懒标记向下传,并更新下方结点的值

以上就是pushdown操作的基本内容

模板:

void pushdown(int u)
{
    auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    if (root.add) // 当前结点有懒标记 向下传递
    {
        left.add += root.add, left.sum += (i64)(left.r - left.l + 1) * root.add;
        right.add += root.add, right.sum += (i64)(right.r - right.l + 1) * root.add;
        root.add = 0;
    }
}

扫描线法

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

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

相关文章

远场Far-Field beamforming与近场Near-Field beamforming有何关系

这里写目录标题 UPA![在这里插入图片描述](https://img-blog.csdnimg.cn/170e1282d2d6424595263daf77707234.png)写在前面Channel Estimation for Extremely Large-Scale Massive MIMO:Far-Field, Near-Field, or Hybrid-Field?Far Field modelNear Field model UPA 写在前面…

Java内存空间(学习随笔)

1、程序运行中栈可能会出现两种错误 StackOverFlowError&#xff1a; 若栈的内存大小不允许动态扩展&#xff0c;那么当线程请求栈的深度超过当前 Java 虚拟机栈的最大深度的时候&#xff0c;就抛出 StackOverFlowError 错误。OutOfMemoryError&#xff1a; 如果栈的内存大小可…

音视频方法技术有哪些?H.265技术详解

H.265发展背景 H.264虽然是一个划时代的数字视频压缩标准&#xff0c;但是随着数字视频产业链的高速发展&#xff0c;H.264的局限性逐步显现&#xff0c;并且由于H.264标准核心压缩算法的完全固化&#xff0c;并不能够通过调整或扩充来更好地满足当前高清数字视频应用。 视频…

电子书制作软件Vellum mac中文版特点

Vellum mac是一款专业的电子书制作软件&#xff0c;它可以帮助用户将文本文件转换为高质量的电子书&#xff0c;支持多种格式&#xff0c;包括EPUB、MOBI、PDF等。Vellum具有直观的用户界面和易于使用的工具&#xff0c;可以让用户快速地创建和发布电子书。 Vellum mac软件特点…

基层医院信息管理系统源码 his系统全套成品源码带电子病历4级

基层医院his系统源码 二级医院信息管理系统源码&#xff0c;演示自主版权&#xff0c;云端SaaS服务 技术细节&#xff1a; 前端&#xff1a;AngularNginx 后台&#xff1a;JavaSpring&#xff0c;SpringBoot&#xff0c;SpringMVC&#xff0c;SpringSecurity&#xff0c;MyBa…

【MySQL】深入解析MySQL双写缓冲区

原创不易&#xff0c;注重版权。转载请注明原作者和原文链接 文章目录 为什么需要Doublewrite BufferDoublewrite Buffer原理Doublewrite Buffer和redo logDoublewrite Buffer相关参数总结 在数据库系统的世界中&#xff0c;保障数据的完整性和稳定性是至关重要的任务。为了实现…

web 基础和http 协议

一、域名 域名的概念 IP地址不易记忆&#xff0c;域名方便记住&#xff0c;以便于用户进行搜索访问 早期使用Hosts文件解析域名地址 缺点&#xff1a; ① 主机名称重复 ② 主机维护困难 DNS&#xff08;Domain Name System&#xff09;域名系统 ① 分布式 将一个大的数…

【AN-Animate教程——熟悉工作区】

【AN-Animate教程——熟悉工作区】 初始页面创建舞台主舞台界面其他常用板块 本篇内容&#xff1a;Animate用途 重点内容&#xff1a;熟悉工作区&#xff0c;以及基本操作 工 具&#xff1a;Adobe Animate 2022 初始页面 在初始页面当中&#xff0c;我们可以看到一个忍者和一个…

使用VS编译Redis源码报错

使用Redis源码版本,解压工程右键生成hiredis项目正常,编译Win32_Interop项目报下图错误(error C2039:system_error:不是std成员;error C3861: system_category:找不到标识符) 解决办法:在Win32_variadicFunctor.cpp和Win32_FDAPI.cpp添加 #include <system_error> ,再右键…

k8s 集群部署 kubesphere

一、最小化部署 kubesphere 1、在已有的 Kubernetes 集群上部署 KubeSphere&#xff0c;下载 YAML 文件: wget https://github.com/kubesphere/ks-installer/releases/download/v3.4.0/kubesphere-installer.yaml wget https://github.com/kubesphere/ks-installer/releases/…

204318-14-9,依多曲肽,DOTA-TOC

DOTA-[Tyr3]-Octreotide&#xff0c;依多曲肽,DOTA-(酪氨酸3)-奥曲肽是一种重要的多肽分子&#xff0c;其结构与奥曲肽类似&#xff0c;具有多种重要的药理作用。由于其具有大量的羧基官能团和醇羟基官能团&#xff0c;可以与各种放射性核素结合&#xff0c;因此被广泛应用于放…

基于springboot实现旅游网站管理平台系统项目【项目源码+论文说明】

基于springboot实现旅游网站平台管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;网络快速发展、人民生活的快节奏都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;旅游管理系统当然也不能排除在外。旅游管理系统是以实际运用为开发背…

关于竞品分析怎么做?掌握这5点就够了!

大家好&#xff0c;我是设计师l1m0&#xff0c;今天要给大家分享的竞品分析相关知识。 在竞争激烈的市场中&#xff0c;了解竞争对手并且在产品开发和市场营销中制定明智的策略至关重要。这正是产品竞品分析的目的所在。本文将详细介绍如何进行产品竞品分析&#xff0c;以及通…

基于Springboot实现口腔牙诊所管理平台项目【项目源码+论文说明】计算机毕业设计

基于Springboot实现口腔牙诊所管理平台演示 摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;口腔管理平台当然也不能排除在外。口腔管理平台是以实际运用为开发背景&…

2024年浙大MBA项目必报名的三个理由

近期是2024年研究生考试网上报名的时间&#xff0c;每一位考生其实都要在这个时间段内最终确定自己的报考院校和专业&#xff0c;无论出于什么样的理由&#xff0c;杭州达立易考教育认为自己的选择都会直接关系到未来三年读书甚至于此生长期的影响&#xff0c;对于MBA等在职类考…

LiveGBS流媒体平台GB/T28181功能-国标设备通道分享手机PC浏览器观看直播

LiveGBS流媒体平台GB/T28181功能-国标设备通道分享手机PC浏览器观看直播 1、 国标设备列表1.1、 查看通道1.2、 开启分享1.3、访问分享页面 2、搭建GB28181视频直播平台 1、 国标设备列表 1.1、 查看通道 1.2、 开启分享 1.3、访问分享页面 2、搭建GB28181视频直播平台 支持 W…

PMP证书已经过续费期了,还有必要再考一次吗?

在3年内需要续费&#xff0c;并且还有一年的证书缓冲期。我认为除了必须要续费外&#xff0c;这并不是非常必要。 已经过去了4年&#xff0c;如果当初考证是因为需要找工作或公司的要求&#xff0c;那么项目管理知识应该已经掌握得差不多了。现在已经有了一份稳定的工作&#…

融资融券利率攻略,最低可以降至4.xx%!

对于融资融券业务而言并不是券商越大&#xff0c;排名越靠前&#xff0c;两融业务就越好&#xff0c;各家券商对两融业务的投入都是不一样的&#xff0c;差异也很大&#xff0c;能做到的最低利率也不尽相同&#xff0c;有的券商500w融资利率都只能做到5.5%&#xff0c;极个别券…

算法通关村第17关【白银】| 贪心高频问题

区间问题 1. 会议室&#xff08;判断区间是否重叠&#xff09; 思路&#xff1a;很容易理解一个人不可能同时出席两场会议&#xff0c;也就是会议时间不能重叠。先按照开始时间排序&#xff0c;逐个比较下一个会议开始时间是否大于前一个会议的结束时间 public static boolean…

计算机视觉和机器视觉有什么区别?

人工智能是一个概念性术语&#xff0c;涵盖了若干特定技术。本文中&#xff0c;我们将探讨机器视觉&#xff08;MV&#xff09;和计算机视觉&#xff08;CV&#xff09;。二者都涉及可视化输入的摄取和解释&#xff0c;因此&#xff0c;了解这些重叠技术的优势、约束和最佳应用…