线段树的学习记录

本文详细介绍线段树的数据结构,包括其基本概念、应用场景、代码实现(如建树、更新及查询操作),以及时间与空间复杂度分析。适用于解决区间查询与更新问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树的学习记录

 

1、区间查询:询问某段区间的某些性质(极值、求和、etc

2、区间更新:某些操作影响了某些区间(统一加一个值)

3、三个问题: 更新点,查询区间

更新区间,查询点

更新区间,查询区间

 

例如:一个长度为N的数组a[1]~a[n]:

我们每次对该数组有一些操作:

1、修改数组中某个元素的值

1,5,4,1,6---(a[2]=3)---> 1,3,4,1,6

2、询问数组中某段区间的最大值

1,5,4,1,6---(max(1,4)=?)---> 5

3、询问数组中某段区间的和

1,5,4,1,6---(sum(3,5)=?)---> 11

 

如果只有一次询问?

枚举相应区间内的元素,输出答案   O(N)

更多的询问?

Q次询问,O(NQ)  That's too SLOW!

线段树——在O(log2N)的时间内完成每次操作 O(Qlog2N)

Less than 1 second when N=Q=100000


线段树的本质是一棵二叉树,不同于其它二叉树,线段树的每一个节点记录的是一段区间的信息。

对于任一非叶子节点,若该区间为[L,R],则
左儿子为[L,(L+R)/2]
右儿子为[(L+R)/2+1,R]


每一个节点记录的信息?
struct Tree
{
   int left,right;     //区间的端点
   int max,sum;   //视题目要求而定
};


线段树——代码实现(建树)

void build(int id,int l,int r){
		tree[id].left=l; tree[id].right=r;
		if (l==r)
		{
			tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
			tree[id].max=max(tree[id*2].max,tree[id*2+1].max;
		}
		else
		{
			int mid=(l+r)/2;
			build(id*2,l,mid);
			build(id*2+1,mid+1,r);
			tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
			tree[id].max=max(tree[id*2].max,tree[id*2+1].max;
		}
	}

如果原数组从a[1]~a[n],调用build(1,1,n)即可。


线段树——代码实现(更新)

更新某个点的数值,并维护相关点的信息

void update(int id,int pos,int val){
		if (tree[id].left==tree[id].right)
		{
			tree[id].sum=tree[id].max=val;
		}
		else
		{
			int mid=(tree[id].left+tree[id].right)/2;
			if (pos<=mid) update(id*2,pos,val);
			else update(id*2+1,pos,val);
			tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
			tree[id].max=max(tree[id*2].max,tree[id*2+1].max)
		}
	}

若更新a[k]的值为val,调用update(1,k,val)即可。


查询某区间内元素的和或最大值(以总和为例)

void query(int id,int l,int r){
		if (tree[id].left==l&&tree[id].right==r)
			return tree[id].sum; //询问总和
		else
		{
			int mid=(tree[id].left+tree[id].right)/2;	
			if (r<=mid) return query(id*2,l,r);
			else if (l>mid) return query(id*2+1,l,r)
			else
			   return query(id*2,l,mid)+query(id*2+1,mid+1,r);
		}
	}

调用query(1,l,r)即可查询[l,r]区间内元素的总和。

线段树——空间复杂度

更新操作:由于总是一条路径从根到某个叶子,而树的深度为log2N,因而为O(log2N)

查询操作:每层被访问的节点不超过4个,因而同样为O(log2N)


线段树——空间复杂度

设长度为N的数组在线段树中,编号最靠右的节点编号为F(N)
若N=2n, F(N)=2(n+1)
若N=2(n+1),F(N)=2(n+2)


因而对于2n<=N<=2(n+1),有
2(n+1)<=F(N)<=2(n+2)
F(N)<=4*N

1、线段树可以做很多很多与区间有关的事情……
2、空间复杂度~O(N*4),每次更新和查询操作的复杂度都是O(logN)。


3、在更新和查询区间[l,r]的时候,为了保证复杂度是严格的O(logN)必须在达到被[l,r]覆盖的区间的结点时就立即返回。而为了保证这样做的正确性,需要在这两个过程中做一些相关的“懒”操作。


“懒操作”在更新区间的有关问题上至关重要。

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值