高级数据结构—线段树(一)

学线段树的原因是因为cf的一道题目始终想不出来怎么优化,后来知道区间查询和修改要用到线段树。。。

原题:Iva & Pav

线段树的作用

  1. 区间最值查询:可以高效地找到给定区间内的最大值、最小值等。

  2. 区间和查询:可以高效地计算给定区间内元素的和、积等。

  3. 区间更新:可以高效地对给定区间内的元素进行更新操作,如增加一个固定值、赋值等。

  4. 区间覆盖:可以将给定区间内的元素全部赋值为一个固定值。

  5. 区间合并:可以将多个区间合并成一个区间,快速地进行区间合并操作。

  6. 区间离散化:可以将区间内的元素进行离散化处理,方便进行查询和统计操作。

  7. 区间交集:可以快速地找到多个区间之间的交集

线段树和树状数组的区别 

 刚学完树状数组来学线段树,一开始还不知道他们具体的差别在哪里,那么以下是我的理解。

1.树状数组是前缀和优化,要用到前缀和的时候较为方便。

2.树状数组用来进行单点修改,区间查询;或者区间修改,单点查询较为方便,而区间查询和区间修改较为复杂,因此可以用线段树优化。

3.线段树适用于需要频繁的区间查询和更新操作的问题,如区间最值、区间和等,能够灵活处理各种区间操作。

4.树状数组适用于一维数组的前缀和查询和更新操作,对于简单的区间操作也能够提供高效的解决方案。

例题: 

最大数

题目链接:最大数

直接看代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
//单点插入,区间查询
const int N = 2e5+5;
struct node{
	int l,r;
	int v;
}tr[N*4];

int m,p;

//子节点的信息更新父节点
void pushup(int u){
	tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);
}

//u为当前线段树节点编号
void build(int u,int l,int r){
	tr[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为根节点,区间[l,r]中的最大值
int query(int u, int l, int r) {
    //      Tl-----Tr
    //   L-------------R   
    //1.不必分治,直接返回
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;

    int mid = tr[u].l + tr[u].r >> 1;
    int v = 0;
    //     Tl----m----Tr
    //        L-------------R 
    //2.需要在tr的左区间[Tl, m]继续分治
    if(l <= mid) v = query(u << 1, l, r);

    //     Tl----m----Tr
    //   L---------R 
    //3.需要在tr的右区间(m, Tr]继续分治
    if(r > mid) v = max(v, query(u << 1 | 1, l, r));

    //     Tl----m----Tr
    //        L-----R 
    //2.3涵盖了这种情况
    return v;
}

//u为节点编号,x为修改位置,v为修改的值
void modify(int u,int x,int v){
	if(tr[u].l==tr[u].r)tr[u].v=v;//叶子节点,递归出口
	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);//回溯,子节点的信息更新父节点
	}
}

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	//n表示树中节点个数,last表示上一次查询的结果
	int n=0,last=0;
	cin>>m>>p;

	//初始化线段树,节点的区间最多为[1,m]
	build(1,1,m);

	while(m--){
		char op;cin>>op;
		if(op=='A'){//添加节点
			int t;cin>>t;
			//在n+1处插入
			modify(1,n+1,(t+last)%p);
			//节点个数+1
			n++;
		}
		else {
			int l;cin>>l;
			//查询[n - L + 1, n]内的最大值,u = 1,即从根节点开始查询
			last=query(1,n-l+1,n);
			cout<<last<<"\n";
		}
	}

	return 0;
}

你能回答这些问题吗

题目链接:你能回答这些问题吗

如图:

如图,假设我们要求区间的最大子段和,有三种情况:

1.包含所有左半边,部分右半边----->左半边的区间和+右半边的前缀和

2.包含所有右半边,部分左半边----->右半边的区间和+左半边的后缀和

3.中间的一部分----->左半边的后缀和+右半边的前缀和

因此我们的结构体要记录四个信息:

struct node{
	int l,r;
	int sum;//[l,r]的区间和
	int lmax;//最大前缀和
	int rmax;//最大后缀和
	int tmax;//区间[l,r]最大连续子段和
}tr[N*4];

 同时pushup函数根据上图可以推出:(重载函数)

//u表示该节点,l表示该节点的左子树,r表示该节点的右子树
void pushup(node &u,node &l,node &r){
	u.sum=l.sum+r.sum;
	//三种最大连续子段和的情况
	u.lmax=max(l.lmax,l.sum+r.lmax);
	u.rmax=max(r.rmax,r.sum+l.rmax);
	u.tmax=max({l.tmax,r.tmax,l.rmax+r.lmax});
}

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

代码附上:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5+5;
int w[N];
int n,m;
struct node{
	int l,r;
	int sum;//[l,r]的区间和
	int lmax;//最大前缀和
	int rmax;//最大后缀和
	int tmax;//区间[l,r]最大连续子段和
}tr[N*4];

//u表示该节点,l表示该节点的左子树,r表示该节点的右子树
void pushup(node &u,node &l,node &r){
	u.sum=l.sum+r.sum;
	//三种最大连续子段和的情况
	u.lmax=max(l.lmax,l.sum+r.lmax);
	u.rmax=max(r.rmax,r.sum+l.rmax);
	u.tmax=max({l.tmax,r.tmax,l.rmax+r.lmax});
}

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

void build(int u,int l,int r){
	if(l==r)tr[u]={l,r,w[r],w[r],w[r],w[r]};//找到叶子节点
	else{
		tr[u]={l,r};//设当前区间为[l,r]
		int mid=l+r>>1;
		build(u<<1,l,mid);//左子树
		build(u<<1|1,mid+1,r);//右子树
		pushup(u);//修改父节点
	}
}

//每次从1号节点开始找,找到位置位于x的数,并把它修改为v
void modify(int u,int x,int v){
	if(tr[u].l==x && tr[u].r==x)tr[u]={x,x,v,v,v,v};
	else{
		int mid=tr[u].l+tr[u].r>>1;
		if(x<=mid)modify(u<<1,x,v);//x位于当前区间的左半子区间
		else modify(u<<1|1,x,v);//x位于当前区间的右半子区间
		pushup(u);//修改父节点的相关信息
	}
}

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

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>w[i];
	build(1,1,n);//建树

	int k,x,y;
	while(m--){
		cin>>k>>x>>y;
		if(k==1){//查询
			if(x>y)swap(x,y);
			cout<<query(1,x,y).tmax<<"\n";
		}
		else modify(1,x,y);//修改
	}

	return 0;
}

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

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

相关文章

Leetcode算法训练日记 | day34

专题九 贪心算法 一、K次取反后最大化的数组和 1.题目 Leetcode&#xff1a;第 1005 题 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个…

关于Spring事务管理之默认事务间调用问题

由事务的传播行为我们知道, 如果将方法配置为默认事务REQUIRED在执行过程中Spring会为其新启事务REQUIRES_NEW, 作为一个独立事务来执行. 由此存在一个问题。 如果使用不慎, 会引发org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back bec…

ACE框架学习

目录 ACE库编译 ACE Reactor框架 ACE_Time_Value类 ACE_Event_Handler类 ACE定时器队列类 ACE_Reator类 ACE Reactor实现 ACE_Select_Reactor类 ACE_TP_Reactor类 ACE_WFMO_Reactor类 ACE库编译 首先去ACE官网下载安装包&#xff0c;通过vs2017或者2019进行编译&#x…

【洛谷 P8605】[蓝桥杯 2013 国 AC] 网络寻路 题解(图论+无向图+组合数学)

[蓝桥杯 2013 国 AC] 网络寻路 题目描述 X X X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包&#xff0c;为了安全起见&#xff0c;必须恰好被转发两次到达目的地。该包可能在任意一个节点产生&#xff0c;我们需要知道该网络中一共有多少种…

10.接口自动化测试学习-Pytest框架(2)

1.mark标签 如果在每一个模块&#xff0c;每一个类&#xff0c;每一个方法和用例之前都加上mark标签&#xff0c;那么在pytest运行时就可以只运行带有该mark标签的模块、类、接口。 这样可以方便我们执行自动化时&#xff0c;自主选择执行全部用例、某个模块用例、某个流程用…

数据分析专家能力模型

招式&#xff1a;懂商业&#xff08;业务能力&#xff09; 外功更偏重于技能&#xff0c;首先需要懂招式&#xff0c;即懂商业&#xff0c;数据分析最终是为业务服务的&#xff0c;无论是互联网企业准求的用户增长和UJM分解&#xff0c;还是传统企业追求的降本增效和精细化运营…

appium相关的知识

>adb shell dumpsys window | findstr mCurrentFocus adb devices # 实例化字典 desired_caps = dict() desired_caps[platformName] = Android desired_caps[platformVersion] = 9 # devices desired_caps[deviceName] = emulator-5554 # 包名 desired_caps[appPackage] …

重建大师出现“密集匹配失败”的情况是什么原因?

答&#xff1a;一般出现密集匹配失败的情况&#xff0c;就是瓦块连接点过少&#xff0c;空瓦块边缘瓦块等原因导致。遇见这种情况&#xff0c;确定是边缘瓦块导致后&#xff0c;就可以不用管&#xff0c;不是模型主体&#xff0c;不影响成果。 重建大师是一款专为超大规模实景三…

MySQL__索引

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a; MySQL__索引&#xff09; ⏱️ 创作时间&#xff1a;2024年04月23日 ———————————————— 索引介绍…

消消乐算法总结

前言 最近在工作中遇到一个问题&#xff0c;做一个消消乐的demo项目&#xff0c;连续相同数目超过四个后就要消除。我在网上看了很多解决方案&#xff0c;有十字形&#xff0c;横向&#xff0c;纵向&#xff0c;梯形搜索。越看越迷糊。这不是用一个BFS就能解决的问题吗&#x…

MySQL数据库进阶篇一(存储引擎、索引)

目录 一、存储引擎1.1、MySQL体系结构&#xff1a;连接层&#xff0c;Server层&#xff0c;引擎层&#xff0c;存储层1.2、存储引擎1.2.1、存储引擎&#xff1a;InnoDB(MySQL 5.5后默认的存储引擎)1.2.2、存储引擎&#xff1a;MyISAM (MySQL早期默认存储引擎)1.2.3、存储引擎&a…

数据可视化———Tableau

基本认识&#xff1a; 维度&#xff1a;定性—字符串文本&#xff0c;日期和日期时间等等 度量&#xff1a;定量—连续值&#xff0c;一般属于数值 数据类型&#xff1a; 数值 日期/日期时间 字符串 布尔值 地理值 运算符 算数运算符&#xff1a;加减乘除,%取余&#xff0c;…

【Flask】Flask中HTTP请求与接收

一、接收http请求与返回响应 在Flask中&#xff0c;可以通过app.route装饰器来定义路由函数。 app.route(/BringGoods,methods [POST, GET]) GET请求&#xff1a;使用request.args.get(key)或者request.values.get(key)来获取URL中的参数。 POST请求&#xff1a; 使用req…

Python自学之路--001:Python + PyCharm安装图文详解教程

目录 1、概述 2、Python解释器 2.1、下载 2.2、Python安装 2.3、Python环境变量配置&#xff0c;必选项 3、PyCharm安装 3.1、PyCharm下载 3.2、PyCharm安装 4、建一个Hello World 5、Phcarm设置 5.1、Phcarm汉化 5.2、Phcarm工具栏显示在顶部 5.3、Phcarm通过pip安…

【QT学习】9.绘图,三种贴图,贴图的转换,不规则贴图(透明泡泡)

一。绘图的解释 Qt 中提供了强大的 2D 绘图系统&#xff0c;可以使用相同的 API 在屏幕和绘图设备上进行绘制&#xff0c;它主要基于QPainter、QPaintDevice 和 QPaintEngine 这三个类。 QPainter 用于执行绘图操作&#xff0c;其提供的 API 在 GUI 或 QImage、QOpenGLPaintDev…

linux18:进程等待

进程等待的必要性 1&#xff1a;子进程创建的目的是要完成父进程指派的某个任务&#xff0c;当子进程运行完毕退出时&#xff0c;父进程需要通过进程等待的方式&#xff0c;回收子进程资源&#xff0c;获取子进程退出信息&#xff08;子进程有无异常&#xff1f;没有异常结果是…

研究发现:提示中加入数百个示例显著提升大型语言模型的性能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

人工智能时代的关键技术:深入探索向量数据库及其在AI中的应用

文章目录 1. 理解向量数据库&#xff1a;二维模型示例2. 向量数据库中的数据存储与检索3. 向量数据库如何工作&#xff1f;4. 向量数据库如何知道哪些向量相似&#xff1f; 在人工智能技术日益成熟的当下&#xff0c;向量数据库作为处理和检索高维数据的关键工具&#xff0c;对…

LlamaIndex 加 Ollama 实现 Agent

AI Agent 是 AIGC 落地实现的场景之一&#xff0c;与 RAG 不同&#xff0c;RAG 是对数据的扩充&#xff0c;是模型可以学习到新数据或者本地私有数据。AI Agent 是自己推理&#xff0c;自己做&#xff0c;例如你对 AI Agent 说我要知道今天上海的天气怎么样&#xff0c;由于 AI…

WSL2无法ping通本地主机ip的解决办法

刚装完WSL2的Ubuntu子系统时&#xff0c;可能无法ping通本地主机的ip&#xff1a; WSL2系统ip&#xff1a; 本地主机ip&#xff1a; 在powershell里输入如下的命令&#xff1a; New-NetFirewallRule -DisplayName "WSL" -Direction Inbound -InterfaceAlias &quo…