Per completare la risposta di ngoaho91.
Il modo migliore per risolvere questo problema è usare la struttura dei dati di Segment Tree. Ciò consente di rispondere a tali query in O (log (n)), ciò significherebbe che la complessità totale del proprio algoritmo sarebbe O (Q logn) dove Q è il numero di query. Se si è utilizzato l'algoritmo ingenuo, la complessità totale sarebbe O (Q n), che è evidentemente più lento.
Tuttavia, c'è un inconveniente nell'utilizzo di Segment Trees. Richiede molta memoria, ma molte volte ti interessa meno della memoria che della velocità.
Descriverò brevemente gli algoritmi utilizzati da questo DS:
L'albero del segmento è solo un caso speciale di un albero di ricerca binaria, in cui ogni nodo contiene il valore dell'intervallo a cui è assegnato. Al nodo radice, viene assegnato l'intervallo [0, n]. Al bambino sinistro viene assegnato l'intervallo [0, (0 + n) / 2] e il bambino destro [(0 + n) / 2 + 1, n]. In questo modo verrà costruito l'albero.
Crea albero :
/*
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.
}
}
Struttura query
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.
}
Se hai bisogno di ulteriori spiegazioni, fammelo sapere.
BTW, Segment Tree supporta anche l'aggiornamento di un singolo elemento o di un intervallo di elementi in O (log n)