#include <fstream>
#include <climits>
using namespace std;
// nod is the root and it corresponds to all the array [0, n)
void update(long int nod, long int st, long int dr,
long int poz, long int val, long int *aint) {
// If st == dr it means that I found the place where
// the number should be inserted
if (st == dr) {
aint[nod] = val;
} else {
// Calculate the middle
long int mid = (st + dr) / 2;
// Continue to search for the right position
// either in the left subtree
if (poz <= mid) {
update(nod * 2, st, mid, poz, val, aint);
// or in the right subtree
} else {
update(nod * 2 + 1, mid + 1, dr, poz, val, aint);
}
// Keep in the tree the minimum between the two subtrees
aint[nod] = aint[nod * 2] < aint[nod * 2 + 1]
? aint[nod * 2] : aint[nod * 2 + 1];
}
}
// Start from root and go down until I find the right interval [a, b]
void query(long int nod, long int st, long int dr,
long int a, long int b, long int *aint, long int *minimum) {
// I found the right interval
if (a <= st && dr <= b) {
*minimum = *minimum < aint[nod] ? *minimum : aint[nod];
// I have to keep searching
} else {
long int mid = (st + dr) / 2;
// either in the leftsubtree
if (a <= mid) query(nod * 2, st, mid, a, b, aint, minimum);
// or in the right subtree
if (b > mid) query(nod * 2 + 1, mid + 1, dr, a, b, aint, minimum);
}
}
int main()
{
ifstream fin("rmq.in");
ofstream fout("rmq.out");
// Initialize variables
long int n, m, x, y, minimum;
long int *aint;
fin >> n >> m;
aint = new long int[3 * n];
// Read elements and update
for (int i = 1; i <= n; i++) {
fin >> x;
update(1, 1, n, i, x, aint);
}
// Read intervals and answer querry
for (int i = 1; i <= m; i++) {
fin >> x >> y;
minimum = INT_MAX;
query(1, 1, n, x, y, aint, &minimum);
fout << minimum << "\n";
}
delete[] aint;
fin.close();
fout.close();
return 0;
}