线段树求最值

问题描述:

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q.
Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i
Lines N+2..N+Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.

Output

Lines 1..Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.



样例输入:

6 3
1
7
3
4
2
5
1 5
4 6
2 2

样例输出:

6
3
0

原因分析:

用线段树求区间最值。


解决方案:

#include "stdio.h"
#include "algorithm"
using namespace std;
const int N=5*1e4+110;
int d[N],x[N],a[N];
int n,m;
int lowbit(int x)
{
	return x&(-x);
}
void init()
{
	int i,j;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		d[i]=x[i]=a[i];
		for(j=1;j<lowbit(i);j<<=1)
		{
			d[i]=max(d[i],d[i-j]);
			x[i]=min(x[i],x[i-j]);
		}
	}
}
int find(int l,int r)
{
	int maxx,minn;
	minn=maxx=a[r];
	while(l!=r)
	{
		for(r-=1;r-l>=lowbit(r);r-=lowbit(r))
		{
			maxx=max(maxx,d[r]);
			minn=min(minn,x[r]);
		}
		maxx=max(maxx,a[r]);
		minn=min(minn,a[r]);
	}
	return maxx-minn;
}
int main ()
{
	int i,x,y;
	scanf("%d%d",&n,&m);
	init();
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",find(x,y));
	}
	return 0;
}

### 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]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值