题意很简单,给出一个数目为n的非有序序列,然后有m次查询.对于每次查询输入两个正整数l,r请输出区间[l,r]的最大值与最小值的差值
Input
第一行:输入两个正整数
n,m (1<=n<=50000, 1<=m<=200000 )
;
第二行:输入n个整数 大小范围为[1,100000];
接下来的m行,每次两个正整数l,r (1<=l<=r<=n);
Output
输出区间
[l,r]
最大值与最小值的差值
.
Example Input
6 3 1 7 3 4 2 5 1 5 4 6 2 2
Example Output
6 3 0
区间最值算是比较常见的问题吧,最简单的做法就是直接把区间排序得到a[r]-a[l],但是对于本题大量的数据肯定是要超时的
这时,线段树就要登场了,树中的每个区间都维护着自身所在区间的最大值和最小值
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5e4 + 10;
struct tree
{
int l, r;
int max, min;
}STree[N << 2];
int MAX, MIN;
void Build(int l, int r, int k)
{
STree[k].l = l;
STree[k].r = r;
if(l == r)
{
scanf("%d", &STree[k].max);
STree[k].min = STree[k].max;
return;
}
int mid = (l + r) >> 1;
Build(l, mid, k << 1);
Build(mid + 1, r, k << 1 | 1);
STree[k].max = max(STree[k << 1].max, STree[k << 1 | 1].max);
STree[k].min = min(STree[k << 1].min, STree[k << 1 | 1].min);
}
void Query(int l, int r, int k)
{
if(l == STree[k].l && r == STree[k].r)
{
MAX = max(MAX, STree[k].max);
MIN = min(MIN, STree[k].min);
return;
}
int mid = (STree[k].l + STree[k].r) >> 1;
int t = 0;
if(r <= mid)
Query(l, r, k << 1);
else if(l > mid)
Query(l, r, k << 1 | 1);
else
{
Query(l, mid, k << 1);
Query(mid + 1, r, k << 1 | 1);
}
}
int main()
{
int n, m, l, r;
scanf("%d%d", &n, &m);
Build(1, n, 1);
while(m--)
{
scanf("%d%d", &l, &r);
MAX = 0;
MIN = N << 2;
Query(l, r, 1);
printf("%d\n", MAX - MIN);
}
return 0;
}
看网上还有一种做法——RMQ,这玩意其实就是一个DP,不难理解,就是敲起来还真有点费劲,用到了位运算,我参考网上的解说,一番优化后终于写成,时间上比线段树还要快一点
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 5e4 + 3;
int max_[N][21], min_[N][21];
int main()
{
int n, q, l, r;
memset(max_, 0, sizeof(max_));
memset(min_, 0x3f, sizeof(min_));
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i++)
{
scanf("%d", &max_[i][0]);
min_[i][0] = max_[i][0];
}
for(int j = 1; (1 << j) <= n; j++)
{
for(int i = 1; i + (1 << j) - 1 <= n; i++)
{
max_[i][j] = max(max_[i][j-1], max_[i + (1 << (j - 1))][j-1]);
min_[i][j] = min(min_[i][j-1], min_[i + (1 << (j - 1))][j-1]);
}
}
while(q--)
{
scanf("%d%d", &l, &r);
int k = 0, _max, _min;
while((1 << (k + 1)) <= r - l + 1) k++;
_max = max(max_[l][k], max_[r - (1 << k) + 1][k]);
_min = min(min_[l][k], min_[r - (1 << k) + 1][k]);
printf("%d\n",_max - _min);
}
return 0;
}