Para complementar la respuesta de ngoaho91.
La mejor manera de resolver este problema es usar la estructura de datos del Árbol de segmentos. Esto le permite responder a tales consultas en O (log (n)), eso significaría que la complejidad total de su algoritmo sería O (Q logn) donde Q es el número de consultas. Si utilizó el algoritmo ingenuo, la complejidad total sería O (Q n), que obviamente es más lenta.
Sin embargo, existe un inconveniente en el uso de los árboles de segmentos. Ocupa mucha memoria, pero muchas veces te importa menos la memoria que la velocidad.
Describiré brevemente los algoritmos utilizados por este DS:
El árbol de segmentos es solo un caso especial de un árbol de búsqueda binaria, donde cada nodo contiene el valor del rango al que está asignado. Al nodo raíz, se le asigna el rango [0, n]. Al hijo izquierdo se le asigna el rango [0, (0 + n) / 2] y al hijo derecho [(0 + n) / 2 + 1, n]. De esta manera se construirá el árbol.
Crear árbol :
/*
A[] -> array of original values
tree[] -> Segment Tree Data Structure.
node -> the node we are actually in: remember left child is 2*node, right child is 2*node+1
a, b -> The limits of the actual array. This is used because we are dealing
with a recursive function.
*/
int tree[SIZE];
void build_tree(vector<int> A, int node, int a, int b) {
if (a == b) { // We get to a simple element
tree[node] = A[a]; // This node stores the only value
}
else {
int leftChild, rightChild, middle;
leftChild = 2*node;
rightChild = 2*node+1; // Or leftChild+1
middle = (a+b) / 2;
build_tree(A, leftChild, a, middle); // Recursively build the tree in the left child
build_tree(A, rightChild, middle+1, b); // Recursively build the tree in the right child
tree[node] = max(tree[leftChild], tree[rightChild]); // The Value of the actual node,
//is the max of both of the children.
}
}
Árbol de consulta
int query(int node, int a, int b, int p, int q) {
if (b < p || a > q) // The actual range is outside this range
return -INF; // Return a negative big number. Can you figure out why?
else if (p >= a && b >= q) // Query inside the range
return tree[node];
int l, r, m;
l = 2*node;
r = l+1;
m = (a+b) / 2;
return max(query(l, a, m, p, q), query(r, m+1, b, p, q)); // Return the max of querying both children.
}
Si necesita más explicaciones, hágamelo saber.
Por cierto, el árbol de segmentos también admite la actualización de un solo elemento o un rango de elementos en O (log n)