线段树(二)区间最值

区间最值

区间求最值是简单的线段树问题,区间最值也可以用ST表求得,具体问题具体分析.
思想
考虑建树
递归建树,叶节点的最值就是当前节点表示的值
除叶节点外的其他节点最值等于Max(左儿子,右儿子)或是Min(左儿子,右儿子);
给出某个区间后将这个区间分到很多子区间快速求解
举个栗子,还是上一节的[1,10]的树,现在询问[4,7]的最值
由于左右儿子是根据Mid分开的,所以在分配问题时也需要考虑Mid和给定区间的关系
1.左端点大于Mid
代表整个区间在右儿子上,只需询问右儿子
2.右端点小于Mid
代表整个区间在左儿子上,只需询问左儿子
3.跨越左右儿子
在左右儿子的最值取Max或Min
递归可求解,复杂度NlogN
代码
#include<cstdio>
#include<iostream>
#include<iostream>
using namespace std;
const int Maxn=100001;
#define mid (l+r)/2
#define lc o<<1
#define rc (o<<1)+1

struct node{int mi;}point[Maxn*4];

int t,n,x,y,a[Maxn];

int query(int l,int r,int o,int x,int y)
{
	if(l==r)return point[o].mi;
	if(x==l&&y==r) return point[o].mi;
	else if(y<=mid) return query(l,mid,lc,x,y);
	else if(x>mid) return query(mid+1,r,rc,x,y);
	else return min(query(l,mid,lc,x,mid),query(mid+1,r,rc,mid+1,y));
}

void build(int l,int r,int o)
{
	if(l==r){point[o].mi=a[l];return;}
	build(l,mid,lc);
	build(mid+1,r,rc);
	point[o].mi=min(point[lc].mi,point[rc].mi);
	return;
}

int main()
{
	scanf("%d%d",&n,&t);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	build(1,n,1);
	for(int i=1;i<=t;i++)
	{
		scanf("%d%d",&x,&y);
		printf("%d ",query(1,n,1,x,y));
	}
}


区间最大值把Min操作改成Max即可
End。
### C++ 线段树实现区间查询 #### 构建线段树 为了构建一棵能够维护区间线段树,需要初始化一个大小为 `4 * n` 的数组作为节点存储空间。这里假设输入的是长度为 `n` 的数组 `arr[]`。 ```cpp const int MAXN = 1e5 + 5; int segTree[MAXN << 2]; // 定义线段树结点数量, 使用位运算表示乘法 void build(int node, int start, int end) { if (start == end) { // 叶子节点情况 segTree[node] = arr[start]; return; } int mid = (start + end) >> 1; // 计算中间位置 build(node<<1, start, mid); // 左孩子递归建立 build((node<<1)|1, mid+1, end); // 右孩子递归建立 segTree[node] = max(segTree[node<<1], segTree[(node<<1)|1]); // 合并左右孩子的 } ``` 此部分描述了如何创建一颗线段树来保存给定序列的信息[^1]。 #### 区间查询 当完成线段树的构造之后,就可以利用它来进行高效的区间查询操作: ```cpp int queryMax(int node, int start, int end, int L, int R) { if (R < start || end < L) return INT_MIN; // 当前范围完全不在询问范围内 if (L <= start && end <= R) return segTree[node]; // 范围被完全覆盖的情况 int mid = (start + end) >> 1; int q1 = queryMax(node*2, start, mid, L, R); int q2 = queryMax(node*2+1, mid+1, end, L, R); return max(q1, q2); // 返回两个子区间的较大者 } ``` 上述函数实现了在线段树上执行区间 `[L,R]` 内的查找功能[^2]。 #### 单点更新 对于单个元素的变化,则可以通过下面的方式快速调整对应的线段树状态: ```cpp void updateNode(int node, int start, int end, int idx, int val){ if(start==end){ arr[idx]=val; segTree[node]=val; return ; } int mid=(start+end)>>1; if(idx<=mid) updateNode(2*node,start,mid,idx,val); else updateNode(2*node+1,mid+1,end,idx,val); segTree[node]=max(segTree[2*node],segTree[2*node+1]); } ``` 这段代码展示了怎样在改变原数组某一位数的同时保持线段树的一致性和有效性[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值