#include <bits/stdc++.h>
#include <fstream>
#define MIN(a, b) ((a < b) ? a : b)
typedef struct {
long a;
long b;
}Query;
/*
* Avem nevoie de len ca variabila globala,
* pentru a putea sorta query-urile
*/
int* preprocess(int* arr, int n, int &processedLength) {
int lastIdx;
int i;
int len = (int) sqrt(n);
int* decomposedMins;
if (n % len == 0) {
decomposedMins = (int*) malloc(sizeof(int) * (n/len));
lastIdx = n/len - 1;
}
else {
decomposedMins = (int*) malloc(sizeof(int) * (n/len + 1));
lastIdx = n/len;
}
for (i = 0; i < n; i += len) {
//int finalProb = (n - i < len) ? (n - i) : len;
decomposedMins[i / len] = *std::min_element(arr + i, arr + i + len);
processedLength++;
}
decomposedMins[lastIdx] = *std::min_element(arr + i - len, arr + n);
return decomposedMins;
}
// bool myCompare(Query q1, Query q2) {
// if (q1.a / len != q2.a / len)
// return q1.a / len < q2.a / len;
// return q1.b < q2.b;
// }
// void sortQueries(Query** queries, int noOfQueries) {
// std::sort (*queries, (*queries) + noOfQueries, myCompare);
// }
void mo(int* arr, Query* queries, int arrLength, int noOfQueries, int* processedMins) {
int len = (int) sqrt(arrLength);
for (int i = 0; i < noOfQueries; i++) {
int L = queries[i].a;
int R = queries[i].b;
int lastStandingMin = __INT_MAX__;
while (L <= R) {
if ((L % len != 0) || (R - L < len)) {
lastStandingMin = MIN(lastStandingMin, arr[L]);
L++;
} else {
lastStandingMin = MIN(lastStandingMin, processedMins[L / len]);
L += len;
}
}
// int currBlockMinLeftIdx = (int) (L / len);
// currBlockMinLeftIdx *= len;
// int currBlockMinRightIdx = currBlockMinLeftIdx + len;
// // Initializam minimul cu minimul query-ului preprocesat aferent
// int lastStandingMin = processedMins[L / len];
// // Il comparam pe acesta cu elementele din stanga pe care nu le acopera
// while (currBlockMinLeftIdx > L) {
// lastStandingMin = MIN(lastStandingMin, arr[L]);
// L++;
// }
// // Il comparam pe acesta cu elementele din dreapta pe care nu le acopera
// while (currBlockMinRightIdx < R) {
// lastStandingMin = MIN(lastStandingMin, arr[R]);
// R--;
// }
printf("%d\n", lastStandingMin);
}
}
void readInput(int*& arr, int &n, int &noOfQueries, Query*& queries, char const *argv) {
// FILE* filePtrIn = fopen(argv, "rt");
// fscanf(filePtrIn, "%d %d", &n, &noOfQueries);
// arr = (int*) malloc(sizeof(int) * n);
// queries = (Query*) malloc(sizeof(Query) * noOfQueries);
// for (int i = 0; i < n; i++)
// fscanf(filePtrIn, "%d", (*arr) + i);
// for (int i = 0; i < noOfQueries; i++) {
// fscanf(filePtrIn, "%d", &queries[i].a);
// fscanf(filePtrIn, "%d", *((*queries) + i).b));
// }
// fclose(filePtrIn);
std::ifstream fin(argv);
fin >> n >> noOfQueries;
arr = (int*) malloc(sizeof(int) * n);
queries = (Query*) malloc(sizeof(Query) * noOfQueries);
for (int i = 0; i < n; i++)
fin >> arr[i];
//printf("%d %d\n", arr[n - 1], noOfQueries);
for(int i = 0; i < noOfQueries; i++) {
fin >> queries[i].a;
fin >> queries[i].b;
}
}
int main(int argc, char const *argv[]) {
// n = 12;
// int test[] = {2, 5, 3, 2, 1, 0, 9, 7, 1, 1, 3, 0, 1, 0, 3, 1};
// len = sqrt(10);
// int processedLength = 0;
freopen("rmq.out", "rw", stdout);
int n, noOfQueries, preprocessedLength = 0;
Query* queries;
int* arr;
readInput(arr, n, noOfQueries, queries, "rmq.in");
// for (int i = 0; i < n; i++)
// printf("%d ", arr[i]);
// printf("\n");
int* preprocessedMins = preprocess(arr, n, preprocessedLength);
mo(arr, queries, n, noOfQueries, preprocessedMins);
// for (int i = 0; i < processedLength; i++) {
// printf("%d ", vrajeala[i]);
// }
// printf("\n");
// Query* queries = (Query*) malloc(sizeof(Query) * 5);
// queries[0].a = 1;
// queries[0].b = 3;
// queries[1].a = 2;
// queries[1].b = 7;
// queries[2].a = 5;
// queries[2].b = 7;
// queries[3].a = 7;
// queries[3].b = 11;
// queries[4].a = 9;
// queries[4].b = 10;
// sortQueries(&queries, 5);
// for (int i = 0; i < 5; i++) {
// printf("query[%d].a = %ld | query[%d].b = %ld\n", i, queries[i].a, i, queries[i].b);
// }
return 0;
}