线段树+懒标记(RMQ问题)

news/2025/2/15 21:18:47/文章来源:https://www.cnblogs.com/dianman/p/18717420

RMQ问题——线段树+懒标记

线段树,基于分治思想,用来维护区间信息的二叉树结构

例如RMQ,区间和,区间GCD问题,在平均 \(O(\log n)\) 的时间复杂度内执行区间修改和查询操作

朴素的线段树的每个节点包含三个元素:左区间,右区间,区间元素统计值(以区间和为例)

struct node{int l,r,sum;
};

对于父节点的编号 \(p\) ,左右孩子的编号即为 \(2*p,2*p+1\)

#define lc p<<1;//定义左儿子
#define rc p<<1|1//定义右儿子

建树时,采用递归的方式,自下而上赋值

node tr[4*N];
void build(int p,int l,int r){tr[p]={l,r,w[l]};//递归到底层,给叶子节点赋值,非叶子节点无效if (l==r) return;//递归出口int m=l+r>>1;//二分树build(lc,l,m);//递归建树左儿子build(rc,m+1,r);//递归建树右儿子tr[p].sum=tr[lc].sum+tr[rc].sum;//递归回溯,赋值非叶子节点的区间统计值
}

有关线段树为什么需要开 \(4*N\) 空间的问题:

因为线段树不一定为满二叉树,所以对于区间 \([1,n]\) ,底层的叶子节点数最差情况为 \(2^{\lfloor\log _2n\rfloor+1}\),所以总节点数最差为

\[2^{\lfloor\log _2n\rfloor+1}*2-1=4*n-1\approx4*n \]


针对区间某一点进行修改,采用递归的方式从树顶进入,到达目标叶子节点然后回溯更新非叶子节点

void update(int p,int x,int k){//p一开始为1,即从根节点进入 x为目标点,k为需要修改为的值if (tr[p].l==x&&tr[p].r==x){//到达需要修改的点tr[p].sum=k;//更新值return;}int m=tr[p].l+tr[p].r>>1;//分治if (x<=m) update(lc,x,k);//x在左半边else update(rc,x,k);//x在右半边tr[p].sum=tr[lc].sum+tr[rc].sum;//回溯更新非叶子节点的区间统计值
}

对某一区间进行统计值的查询,采取拆分和拼凑的办法

  • 如果二分下来的区间能被需要查询的区间完全覆盖,那么直接加上这个区间的统计值即可(拼凑答案的一部分)
  • 左儿子与需要查询的区间有重合,那就递归左子树
  • 右儿子与需要查询的区间有重合,那就递归右子树
int query(int p,int x,int y){if (x<=tr[p].l&&y>=tr[p].r)//能完全覆盖的区间一定是答案的一部分return tr[p].sum;int m=tr[p].l+tr[p].r>>1;int sum=0;if (x<=m) sum+=query(lc,x,y);//访问左子树if (y>m) sum+=query(rc,x,y);//访问右子树return sum;
}

懒惰修改:

修改区间时给非叶子节点添加懒标记,只在必要的条件下下传懒标记,否则一直维持在非叶子节点上

这个操作可以将朴素的区间修改操作的 \(O(n)\) 优化到 \(O(\log n)\)

struct node{int l,r,sum,add;//额外增添懒标记
};
void build(int p,int l,int r){tr[p]={l,r,w[l],0};//建树时,初始化懒标记为0...
}

下传懒标记,区间修改操作:

void pushdown(int p){//下传懒标记if (tr[p].add){tr[lc].sum+=tr[p].add*(tr[lc].r-tr[lc].l+1);//更新左儿子的统计值tr[rc].sum+=tr[p].sum*(tr[rc].r-tr[rc].l+1);//更新右儿子的统计值tr[lc].add+=tr[p].add;//下传给左儿子tr[rc].add+=tr[p].add;//下传给右儿子tr[p].add=0;}
}void update(int p,int x,int y,int k){//更新xy区间的值都增加kif (x<=tr[p].l&&y>=tr[p].r){//如果完全覆盖,直接修改非叶子节点统计值,添加懒标记tr[p].sum+=(tr[p].r-tr[p].l+1)*k;tr[p].add+=k;return;}int m=tr[p].l+tr[p].r>>1;pushdown(p);//下传懒标记if (x<=m) update(lc,x,y,k);//维护左子树if (y>m) update(rc,x,y,k);//维护右子树tr[p].sum=tr[lc].sum+tr[rc].sum;//更新非叶子节点区间统计值
}

同样的,添加了懒标记后,区间查询操作仍然需要下传

int query(int p,int x,int y){if (x<=tr[p].l&&y>=tr[p].r)//能完全覆盖的区间一定是答案的一部分return tr[p].sum;int m=tr[p].l+tr[p].r>>1;pushdown(p);//下传懒标记int sum=0;if (x<=m) sum+=query(lc,x,y);//访问左子树if (y>m) sum+=query(rc,x,y);//访问右子树return sum;
}

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

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

相关文章

撑起计算机视觉半边天的ResNet【论文精读】

ResNet论文精读:深度残差学习如何重塑深度学习一、技术演进背景:深度网络的困境与突破 消失的梯度与退化问题 在ResNet提出之前,深度学习领域已通过VGGNet、GoogLeNet等模型验证了网络深度的重要性。然而,当网络深度超过20层时,研究者发现了一个反直觉现象:更深的网络反而…

2025多校冲刺省选模拟赛13

2025多校冲刺省选模拟赛13\(T1\) A. 逆序对 \(56pts\)原题: luogu P5972 [PA 2019] Desant部分分\(56pts\) :爆搜。点击查看代码 int a[50]; pair<int,ll>ans[50]; struct BIT {int c[50];int lowbit(int x){return x&(-x);}void add(int x,int val){for(int i=x;i…

使用 Git 命令和 Github 前须了解的知识

本文不包括 Git 命令的介绍与使用,只分享 Git 的关键概念与 Github 项目的基本工作流程。作者相信先了解它们对后续的学习和工作大有裨益。(如有错误和建议请大家评论告知)版本控制系统 VCS → Version Control System,版本控制系统 → 一个跟踪文件变化、记录修订情况、协…

leetcode hot 02

解题思路:找祖先从底向上递归后序遍历查找,遇到p,q或者空节点就直接返回对应值,当某个节点的左子树、右子树都返回了值,那么就说明该节点就是最近祖先节点,然后把该节点的值继续往上传,直到根节点返回结果。 /*** Definition for a binary tree node.* public class Tre…

Linux介绍及使用

一、linux介绍 1、Linux是一个免费、开源的操作系统,能多用户、多任务、支持多线程和多CPU的操作系统,相对windows更加稳定,在unix系统的基础上开发的系统; 注解:(1)免费:不要钱 (2)源代码公开 (3)多用户 :可以在不同用户操作 (4)多任务:同时执行多个任务 …

Maven 生命周期 Test 阶段遇到的一些问题

Q:无法使用@Test注解,报错 A:最初pom.xml中使用的Junit版本为3,Java 5于 2004 年发布,引入了注解作为语言的一部分。而Junit 3 是在这之前发布的,因此它无法使用注解,将pom.xml中的版本号改为<version>4.13.2</version>后问题解决,可使用@TestQ:在Maven启…

18. 信号

一、什么是信号在 Linux 中,信号是一种用于通知进程发生了某种事件的机制。信号可以由内核、其它进程或者命令行工具发送给目标进程。Linux 系统中由多种信号,每种信号都用一个唯一的数值表示。例如,常见的信号如下:SIGINT (2):这是当用户在终端按下 Ctrl+C 时发送给前台进…

【专题】DeepSeek技术颠覆or创新共赢,开启Al算法变革元年报告汇总PDF洞察(附原数据表)

原文链接: https://tecdat.cn/?p=39544 在科技飞速迭代的当下,人工智能领域正经历着深刻变革,AI Agent 的发展尤为引人瞩目。 随着数字化进程的加速,全球数据量呈指数级增长,如同为 AI Agent 的发展提供了丰沃土壤。海量数据不仅为模型训练提供了坚实基础,更驱动着 AI A…

Python梯度提升模型GBM生态学研究:SFS、RandomizedSearchCV预测黑腿蜱种群分布丰度可视化-

全文链接:https://tecdat.cn/?p=39232 原文出处:拓端数据部落公众号 广义线性模型一直是揭示自然种群分布和丰度背后生态过程的基础统计框架。然而,随着环境和生态数据的快速增长,分析这些大规模数据集需要更先进的统计方法。梯度提升树等现代机器学习框架,能有效识别复杂…

9.7.5 预测

这里的预测过程不是图\(9\)-$14,应该是下面这幅图,这里有误