/**
https://www.hackerearth.com/practice/data-structures/advanced-data-structures/segment-trees/tutorial/
http://www.geeksforgeeks.org/segment-tree-set-1-range-minimum-query/
*/
#include <stdio.h>
#include <stdlib.h>
void build(int* tree, int a[], int node, int start, int end)
{
if(start == end)
{
// Leaf node will have a single element
tree[node] = a[start];
}
else
{
int mid = (start + end) / 2;
// Recurse on the left child
build(tree, a, 2 * node + 1, start, mid);
// Recurse on the right child
build(tree, a, 2 * node + 2, mid + 1, end);
// Internal node will have the minimum of both of its children
tree[node] = tree[2 * node + 1] < tree[2 * node + 2] ?
tree[2 * node + 1] : tree[2 * node + 2];
}
}
int* createSegmentTree(int a[], int n)
{
int* segmentTree = (int*) malloc((3 * n) * sizeof(int));
build(segmentTree, a, 0, 0, n - 1);
return segmentTree;
}
void destroySegmentTree(int* tree)
{
free(tree);
}
void update(int* tree, int a[], int node, int start, int end, int idx, int val)
{
if(start == end)
{
// Leaf node
a[idx] += val;
tree[node] += val;
}
else
{
int mid = (start + end) / 2;
if(start <= idx && idx <= mid)
{
// If idx is in the left child, recurse on the left child
update(tree, a, 2 * node + 1, start, mid, idx, val);
}
else
{
// if idx is in the right child, recurse on the right child
update(tree, a, 2 * node + 2, mid + 1, end, idx, val);
}
// Internal node will have the minimum of both of its children
tree[node] = tree[2 * node + 1] < tree[2 * node + 2] ?
tree[2 * node + 1] : tree[2 * node + 2];
}
}
void updateValue(int* tree, int a[], int n, int i, int val)
{
int diff = val - a[i];
a[i] = diff;
update(tree, a, 0, 0, n - 1, i, diff);
}
int query(int* tree, int node, int start, int end, int l, int r)
{
if(r < start || end < l)
{
// range represented by a node is completely outside the given range
//return 0;
return 1000001;
}
if(l <= start && end <= r)
{
// range represented by a node is completely inside the given range
return tree[node];
}
// range represented by a node is partially inside and partially outside
// the given range
int mid = (start + end) / 2;
int p1 = query(tree, 2 * node + 1, start, mid, l, r);
int p2 = query(tree, 2 * node + 2, mid + 1, end, l, r);
return (p1 < p2 ? p1 : p2);
}
int queryRange(int* tree, int n, int l, int r)
{
return query(tree, 0, 0, n - 1, l, r);
}
int main()
{
/**
int a[] = {1, 5, 2, 4, 3};
int n = sizeof(a) / sizeof(a[0]);
int* tree = createSegmentTree(a, n);
printf("%d\n", queryRange(tree, n, 0, 4));
printf("%d\n", queryRange(tree, n, 0, 2));
printf("%d\n", queryRange(tree, n, 2, 4));
updateValue(tree, a, n, 4, 1); // pos than value
printf("%d\n", queryRange(tree, n, 3, 4));
destroySegmentTree(tree);
return 0;
*/
int n, m;
FILE* fin = fopen("rmq.in", "r");
FILE* fout = fopen("rmq.out", "w");
fscanf(fin, "%d", &n);
fscanf(fin, "%d", &m);
int* a = (int*) malloc(n * sizeof(int));
for(int i = 0; i < n; i++)
{
fscanf(fin, "%d", &a[i]);
}
int* tree = createSegmentTree(a, n);
int s, d;
for(int i = 0; i < m; i++)
{
fscanf(fin, "%d", &s);
fscanf(fin, "%d", &d);
fprintf(fout, "%d\n", queryRange(tree, n, s - 1, d - 1));
}
free(a);
destroySegmentTree(tree);
return 0;
}