Để bổ sung cho câu trả lời của ngoaho91.
Cách tốt nhất để giải quyết vấn đề này là sử dụng cấu trúc dữ liệu Segment Tree. Điều này cho phép bạn trả lời các truy vấn như vậy trong O (log (n)), điều đó có nghĩa là tổng độ phức tạp của thuật toán của bạn sẽ là O (Q logn) trong đó Q là số lượng truy vấn. Nếu bạn sử dụng thuật toán ngây thơ, tổng độ phức tạp sẽ là O (Q n) rõ ràng là chậm hơn.
Tuy nhiên, có một nhược điểm của việc sử dụng Cây phân đoạn. Nó chiếm rất nhiều bộ nhớ, nhưng rất nhiều lần bạn ít quan tâm đến bộ nhớ hơn là về tốc độ.
Tôi sẽ mô tả ngắn gọn các thuật toán được sử dụng bởi DS này:
Cây phân đoạn chỉ là trường hợp đặc biệt của Cây tìm kiếm nhị phân, trong đó mọi nút giữ giá trị của phạm vi mà nó được gán. Nút gốc, được gán phạm vi [0, n]. Con trái được gán phạm vi [0, (0 + n) / 2] và con phải [(0 + n) / 2 + 1, n]. Bằng cách này, cây sẽ được xây dựng.
Tạo cây :
/*
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.
}
}
Cây truy vấn
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.
}
Nếu bạn cần giải thích thêm, chỉ cần cho tôi biết.
BTW, Segment Tree cũng hỗ trợ cập nhật một phần tử hoặc một phạm vi phần tử trong O (log n)