//线段树维护区间的最大值
//暴力做法O(mn)
//线段树做法O(mlogN)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct Node{
int l;
int r;
int maxv;
}tr[4 * N];
int n;
int m;
int a[N];
void pushUp(int u){
tr[u].maxv = max(tr[u << 1].maxv , tr[u << 1 | 1].maxv);
}
void build(int u , int l , int r){
if (l == r) tr[u] = {l , r , a[l]};
else{
tr[u] = {l , r};
int mid = (l + r) >> 1;
build (u << 1 , l , mid);
build (u << 1 | 1 , mid + 1 , r);
pushUp(u);
}
}
int query(int u , int l , int r){
if (tr[u].l >= l && tr[u].r <= r) return tr[u].maxv;
int mid = (tr[u].l + tr[u].r) >> 1;
int m = -(1 << 32 - 1);
if (l <= mid) m = max(m , query(u << 1 , l , r));
if (r > mid) m = max(m , query(u << 1 | 1 , l , r));
return m;
}
int main (){
scanf ("%d %d" , &n , &m);
for (int i = 1;i <= n;i++) scanf ("%d" , &a[i]);
//建立线段树
build(1 , 1 , n);
int l = 0;
int r = 0;
while(m--){
scanf ("%d %d" ,&l , &r);
printf ("%d\n" , query(1 , l , r));
}
return 0;
}