数列区间最大值


acwing 1270
Time limit:2s
Memory limit:64MB

Problem Description

输入一串数字,给你 M 个询问,每次询问就给你两个数字 X,Y要求你说出 X 到 Y 这段区间内的最大数。

Input

  • 第一行两个整数 N,M表示数字的个数和要询问的次数;
    接下来一行为 N 个数;
    接下来 M 行,每行都有两个整数 X,Y。
    1≤N≤105
    1≤M≤106
    1≤X≤Y≤N
    数列中的数字均不超过231−1

Output

输出共 M 行,每行输出一个数。

Sample Input

10 2
3 2 4 5 6 8 1 2 9 7
1 4
3 8

Sample Output

5
8

线段树解法

AC代码:
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,x[100005]; //原数组
struct Node{
int l,r,w; //线段树的左、右、值
};
Node tree[400005]; //线段树
void build(int num,int l,int r){
if(l == r){ //相等说明已经到了叶子节点
tree[num].l = l,tree[num].r = r,tree[num].w = x[l];return;
}
int mid = (l + r) >> 1;
int lc = num << 1; //乘2是左子树
int rc = num << 1 | 1; //乘2或1是右子树
build(lc,l,mid); //建左子树
build(rc,mid + 1,r); //建右子树
tree[num].l = l,tree[num].r = r,tree[num].w = max(tree[lc].w,tree[rc].w);return; //保存左右子树的最大子(区间最大)
}
int find(int num,int l,int r){
if(tree[num].l == l && tree[num].r == r)
return tree[num].w; //找到目标区间
int mid = (tree[num].l + tree[num].r) >> 1;
int lc = num << 1;
int rc = num << 1 | 1;
if(l > mid)
return find(rc,l,r); //继续在右子树找
else if(r <= mid)
return find(lc,l,r); //继续在左子树找
else return max(find(lc,l,mid),find(rc,mid + 1,r)); //左子树找一段,右子树找一段
}
int main(){
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;++i)
scanf("%d",x + i);
build(1,1,n);
while(m--){
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",find(1,l,r));
}
return 0;
}