第五十八章 线段树(一)

news2025/11/2 9:28:51

第五十八章 线段树(一)

  • 一、树状数组的缺陷
  • 二、线段树的作用
  • 三、线段树的基本构成
      • 1、节点定义
      • 2、线段树的结构
  • 四、线段树的重要函数
    • 1、构造线段树——bulid函数
    • 2、查询区间——query函数
    • 3、单点修改——modify函数
  • 五、例题

一、树状数组的缺陷

在前面两个章节中,我们利用树状数组去维护的是前缀和数组和差分数组。当我们去查询 区间和的时候,我们采用的方法是两个前缀和相减。也就是说,如果我们想求某个区间的性质就必须将其转化为两个前缀的性质相减。只有满足这个条件的时候,我们才能使用树状数组。但是有的性质并不满足这个条件,比如说我们想求一个区间最大值的时候,我们并不能将其转化为两个前缀的最大值相减。

所以说,当我们求某些特殊的区间性质的时候,树状数组就很难做到了。但是如果是求前缀的性质,树状数组还是很好用的。

那么为了解决高效求区间性质的问题,就需要用到今天所讲解的线段树。

二、线段树的作用

线段树能做到的恰恰就是树状数组不能做到的。线段树最重要的作用就是通过 O ( l o g ( n ) ) O(log(n)) O(log(n))的时间复杂度去维护或查询某个区间的性质。

三、线段树的基本构成

1、节点定义

struct Node
{
	int l, r;//区间的左右端点
	int v;//该区间的性质
}

2、线段树的结构

线段树是一个二叉树。假设一个节点代表的区间是 [ l , r ] [l,r] [l,r],然后我们将这个区间一分为2,左边的区间就是该节点的左子树,右边的区间就是该节点的右子树。
如下图所示:
在这里插入图片描述
(选自百度百科)

四、线段树的重要函数

1、构造线段树——bulid函数

void build(int u, int l, int r)
{
	tre[u] = {l, r};
	if(l == r)
		return;
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
}

u u u指的是节点标号, l l l r r r是该节点所代表的区间的左右端点。当我们的根节点标号是 1 1 1的时候,我们的左右子节点分别是 ( 2 ∗ u ) (2*u) (2u) ( 2 ∗ u + 1 ) (2*u+1) (2u+1),如果写成位运算的模式即: ( u < < 1 ) (u<<1) (u<<1) ( u < < 1 ∣ 1 ) (u<<1|1) (u<<1∣1)。最小的区间即区间左端点等于区间右端点的时候,此时该区间所在的树中节点也恰好是我们的叶子节点。

2、查询区间——query函数

在这里插入图片描述
如上图所示,假设我们的线段树维护的是区间的最大值,我们现在的目的是求红色区域所构成的区间的最大值。

想要求红色区间最大值的话,我们只需要找到图中三段的绿色区间的最大值,然后三个区间比较一下即可。

现在我们的难点是如何找到这三个绿色区间。

不难发现,这三个区间都是被红色区间包含的,所以只要某个节点所代表的区间被包含在我们所求区间里,我们就返回这个区间的最值,然后再所有返回的最值中比较一个最大值作为答案。

int query(int u, int l, int r)
{
	if(tre[u].l >= l && tre[u].r <= r)
		return tre[u].v;
	int mid = tre[u].l + tre[u].r >> 1;
	int res = 0;
	if(l <= mid)
		res = query(u << 1, l, r);
	if(r > mid)
		res = max(res, query(u << 1 | 1, l, r));
	return res;
}

3、单点修改——modify函数

单点修改的操作比较麻烦,我们可以将单点修改的操作画成下面的图。
在这里插入图片描述
假设上面这个图的最后一层就是叶子节点。叶子节点所代表的区间就是一个点,所以我们单点修改一定对应着某个叶子节点,我们现在的目的就是去找到这个点。然后对这个点进行修改。

这里还有一个问题,这个单点被包含在若干区间内,当我们修改了这个单点后,所有包含这个点的区间也需要被更新。也就是说我们在回溯的时候,还要利用子节点去更新一下父节点。这个利用子节点更新父节点操作写成: p u s h u p pushup pushup

void pushup(int u)
{
	tre[u].v = max(tre[u << 1].v, tre[u << 1 | 1].v);
}

void modify(int u, int x, int v)
{
	if(tre[u].l == x && tre[u].r == x)
		tre[u].v = v;
	else
	{
		int mid = tre[u].l + tre[u].r >> 1;
		if(x <= mid)
			modify(u << 1, x, v);
		else
			modify(u << 1 | 1, x, v);
		
		pushup(u);
	}
}

五、例题

AcWing1275. 最大数

参考代码:

#include<bits/stdc++.h>
#define endl '\n'
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 2e5 + 10;
struct Node
{
	int l, r;
	int v;
}tre[4 * N];
int m, p;


void build(int u, int l, int r)
{
	tre[u] = {l, r};
	if(l == r)
		return;
	int mid = l + r >> 1;
	build(u << 1, l, mid);
	build(u << 1 | 1, mid + 1, r);
}

int query(int u, int l, int r)
{
	if(tre[u].l >= l && tre[u].r <= r)
		return tre[u].v;
	int mid = tre[u].l + tre[u].r >> 1;
	int res = 0;
	if(l <= mid)
		res = query(u << 1, l, r);
	if(r > mid)
		res = max(res, query(u << 1 | 1, l, r));
	return res;
}

void pushup(int u)
{
	tre[u].v = max(tre[u << 1].v, tre[u << 1 | 1].v);
}

void modify(int u, int x, int v)
{
	if(tre[u].l == x && tre[u].r == x)
		tre[u].v = v;
	else
	{
		int mid = tre[u].l + tre[u].r >> 1;
		if(x <= mid)
			modify(u << 1, x, v);
		else
			modify(u << 1 | 1, x, v);
		
		pushup(u);
	}
}


void solve()
{
	 int n = 0, last = 0;
    scanf("%lld%lld", &m, &p);
    build(1, 1, m);

    int x;
    char op[2];
    while (m -- )
    {
        scanf("%s%lld", op, &x);
        if (*op == 'Q')
        {
            last = query(1, n - x + 1, n);
            printf("%lld\n", last);
        }
        else
        {
            modify(1, n + 1, ((ll)last + x) % p);
            n ++ ;
        }
    }

}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	solve();
}

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

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

相关文章

flink 的 State

目录 一、前言 二、什么是State 2.1&#xff1a;什么时候需要历史数据 2.2&#xff1a;为什么要容错&#xff0c;以及checkpoint如何进行容错 2.3&#xff1a;state basckend 又是什么 三、有哪些常见的是 State 四、 State的使用 五、State backend 5.1 MemoryState…

进程,线程,调度和调度算法基本知识

进程 我们编写的代码只是一个存储在硬盘的静态文件&#xff0c;通过编译后就会生成二进制可执行文件&#xff0c;当我们运行这个可执行文件后&#xff0c;它会被装载到内存中&#xff0c;接着 CPU 会执行程序中的每一条指令&#xff0c;那么这个运行中的程序&#xff0c;就被称…

【C++】内联函数理解

内联函数 内联函数的使用是对于C语言中宏函数的一种改进&#xff0c;他继承了宏的优点并避免了宏的缺点。 宏的优点&#xff1a;a. 代码复用性高 b. 宏函数减少栈帧建立&#xff0c;提高效率 宏的缺点&#xff1a;a. 可读性差 b. 没有类型安全检查 c. 不方便调试 C基本不再建议…

银行数字化转型导师坚鹏:金融数据治理、数据安全政策解读

金融数据治理、数据安全政策解读及大数据应用课程背景&#xff1a; 很多银行存在以下问题&#xff1a; 不知道如何准确理解金融数据治理及数据安全相关政策 不清楚金融数据治理及数据安全相关政策对银行有什么影响&#xff1f; 不清楚如何有效应用金融数据治理及数据安全相关…

软考软件设计师 下午试题二笔记

E-R图基本图形元素 实体 一个实体的存在要以另一个实体存在为前提&#xff0c;这个就是弱实体&#xff0c;比如家属和职工&#xff0c;家属的存在就是依赖于职工 属性 属性带下划线的是主键 联系 三个实体之间的联系 试题二问题一例题 问题二 将er图转成关系模式就是问题二答…

Cell Discovery:人类特异基因促进大脑皮层折叠新机制

在人类进化过程中&#xff0c;新皮层的扩张与智力的提高和认知功能的改善密切相关。这种扩张的一个关键方面是大脑皮层沟回的形成&#xff0c;它使扩张的皮质表面积能够适应有限的颅骨空间。这些进化特征主要依赖于多种神经干细胞和祖细胞亚型及其神经源性分裂产生的更多数量的…

《计算机网络-自顶向下》05. 网络层-控制平面

文章目录路由控制方式每路由控制逻辑集中式控制路由选择算法LS —— 链路状态路由选择算法DV —— 距离向量路由选择算法LS 和 DV 算法的比较自治系统内部路由协议RIPOSPF自治系统外部路由协议&#xff1a;BGP通告 BGP 路由信息选择最好的路由相关术语热土豆选择路由选择算法&a…

Swagger教程

Swagger 目标 Swagger简介【了解】 Springboot整合swagger【掌握】 Swagger 常用注解【掌握】 一、Swagger简介 ​ Swagger 是一系列 RESTful API 的工具&#xff0c;通过 Swagger 可以获得项目的⼀种交互式文档&#xff0c;客户端 SDK 的自 动生成等功能。 ​ Swagger …

TryHackMe-Year of the Owl(Windows渗透测试)

Year of the Owl 当迷宫在你面前&#xff0c;你迷失了方向时&#xff0c;有时跳墙思考是前进的方向。 端口扫描 循例 nmap SMB枚举 smbmap enum4linux也什么都没有 Web枚举 80端口 gobuster扫到一堆403&#xff0c;并没有什么有用的信息 443端口与80端口一致 47001端口依…

【SQL】公网远程访问局域网SQL Server数据库【无公网IP内网穿透】

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 转发自CSDN远程穿透的文章&#xff1a;[无需公网IP&am…

详解以太坊

以太坊原理 以太坊通过建立终极的抽象的基础层-内置有图灵完备编程语言的区块链-使得任何人都能够创建合约和去中心化应用&#xff0c;并在其中设立他们自由定义的所有权规则、交易方式和状态转换函数。 图灵完备&#xff1a;能够运行非常复杂的运算&#xff0c;最简单的理解…

基于共享储能电站的工业用户日前优化经济调度

目录 1 主要内容 共享电站示意图 目标函数 2 部分程序 3 程序结果 4 程序链接 1 主要内容 该程序方法复现《基于共享储能电站的工业用户日前优化经济调度》算例2和算例3&#xff0c;根据共享储能电站的商业运营模式&#xff0c;将共享储能电站应用到工业用户经济优化调度…

〖Python网络爬虫实战⑨〗- 正则表达式基本原理

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

【Linux】用户命令(创建,修改,切换,删除,密码)

目录 1.创建 查看用户信息 查看id 2.修改 修改用户名 修改用户uid 操作前&#xff1a; 操作后 修改组名 操作前&#xff1a; 操作后: 修改组id 操作前&#xff1a; 操作后&#xff1a; 操作前&#xff1a; 操作后: 3.切换用户 4.删除 操作前&#xff1a; 操作…

如何在Spring Boot中使用Spring MVC

目录 1.MVC 2.Spring MVC 3.Spring Boot中使用Spring MVC 3.1.配置 3.1.1.文件配置 3.1.2.代码配置 3.2.使用 3.2.1.映射处理器 3.2.2.传参 3.2.3.参数转换 3.2.4.数据校验 3.2.5.数据模型 3.2.6.视图和解析器 3.2.7.拦截器 1.MVC MVC 是一种常见的软件设计模式…

企业级信息系统开发讲课笔记2.4 利用MyBatis实现条件查询

文章目录零、本节学习目标一、查询需求二、打开MyBatisDemo项目三、对学生表实现条件查询&#xff08;一&#xff09;创建学生映射器配置文件&#xff08;二&#xff09;在MyBatis配置文件里注册学生映射器配置文件&#xff08;三&#xff09;创建学生映射器接口&#xff08;四…

macOS Ventura 13.3.1 (22E261) Boot ISO 原版可引导镜像

本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Linux 中创建可引导介质。 macOS Ventura 13.3.1 为 Mac 提供下…

os库的使用与第三方库安装脚本

os库基本介绍 os 顾名思义&#xff0c;就是与操作系统相关的标准库。如&#xff1a;文件&#xff0c;目录&#xff0c;执行系统命令等。 os库是Python标准库&#xff0c;包含几百个函数 常用路径操作、进程管理、环境参数等几类 路径操作&#xff1a;os.path子库&#xff0…

安捷伦34970A

18320918653 34970A Agilent 34970A 数据采集器|安捷伦数据采集器|34970A 您可信任的测量&#xff1a; 我们把销售良好数字多用表测量引擎嵌入在3槽主机箱中。您能获得优异的测量能力&#xff0c;带有内置信号调整的通用输入&#xff0c;模块化的灵活性&#xff0c;低廉的售…

Ubuntu20.04配置CuckooSandbox环境

Ubuntu20.04配置CuckooSandbox环境 因为最近要做恶意软件分析&#xff0c;阅读论文发现动态分析的效果普遍比静态分析的效果要好一些&#xff0c;所以需要搭建一个动态分析的环境&#xff0c;查阅资料发现Cuckoo Sandbox是不错的自动化分析环境&#xff0c;但是搭建起来还是比…