- Segment Tree Query
中文English
For an integer array (index from 0 to n-1, where n is the size of this array), in the corresponding SegmentTree, each node stores an extra attribute max to denote the maximum number in the interval of the array (index from start to end).
Design a query method with three parameters root, start and end, find the maximum number in the interval [start, end] by the given root of segment tree.
Example 1:
For array [1, 4, 2, 3], the corresponding Segment Tree is:
Input:"[0,3,max=4][0,1,max=4][2,3,max=3][0,0,max=1][1,1,max=4][2,2,max=2][3,3,max=3]",1,2
Output:4
Explanation:
For array [1, 4, 2, 3], the corresponding Segment Tree is :
[0, 3, max=4]
/ \
[0,1,max=4] [2,3,max=3]
/ \ / \
[0,0,max=1] [1,1,max=4] [2,2,max=2], [3,3,max=3]
The maximum value of [1,2] interval is 4
Input:query(root, 1, 1), Output:4
Input:query(root, 1, 2), Output:4
Input:query(root, 2, 3), Output:5
Input:query(root, 0, 2), Output:4
Example 2:
Input:"[0,3,max=4][0,1,max=4][2,3,max=3][0,0,max=1][1,1,max=4][2,2,max=2][3,3,max=3]",2,3
Output:3
Explanation:
For array [1, 4, 2, 3], the corresponding Segment Tree is :
[0, 3, max=4]
/ \
[0,1,max=4] [2,3,max=3]
/ \ / \
[0,0,max=1] [1,1,max=4] [2,2,max=2], [3,3,max=3]
The maximum value of [2,3] interval is 3
Notice
It is much easier to understand this problem if you finished Segment Tree Build first.
解法1:递归。
注意:
- mid必须以root->start和root->end为准,而不是start和end为准。因为线段树就是根据root->start和root->end来划分的。
- start和end都是与mid比较,而不是与root->start和root->end比较。
/**
* Definition of SegmentTreeNode:
* class SegmentTreeNode {
* public:
* int start, end, max;
* SegmentTreeNode *left, *right;
* SegmentTreeNode(int start, int end, int max) {
* this->start = start;
* this->end = end;
* this->max = max;
* this->left = this->right = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param root: The root of segment tree.
* @param start: start value.
* @param end: end value.
* @return: The maximum number in the interval [start, end]
*/
int query(SegmentTreeNode * root, int start, int end) {
if (!root) return 0;
if (start <= root->start && end >= root->end) return root->max;
int mid = root->start + (root->end - root->start) / 2;
int result = 0;
if (start <= mid) {
result = max(result, query(root->left, start, min(mid, end)));
}
if (mid + 1 <= end) {
result = max(result, query(root->right, max(mid + 1, start), end));
}
return result;
}
};
解法2:和解法1类似。参考九章。
区别就是这里查询的start和end一直都没变。为什么可以不变呢?因为最终递归时,比如说选左区间,如果start在左区间,end超出了左区间,那么最终左区间又会继续递归。假如start<新左区间的mid,则继续递归query start和新左区间的左区间,以及新左区间的右区间,而后者已经在[start,end]范围内。
class Solution {
public:
/**
* @param root: The root of segment tree.
* @param start: start value.
* @param end: end value.
* @return: The maximum number in the interval [start, end]
*/
int query(SegmentTreeNode * root, int start, int end) {
if (!root) return 0;
if (start <= root->start && end >= root->end) return root->max;
int mid = root->start + (root->end - root->start) / 2;
int result = 0;
if (start <= mid) {
result = max(result, query(root->left, start, end));
}
if (mid + 1 <= end) {
result = max(result, query(root->right, start, end));
}
return result;
}
};
另外,根据链接:https://blog.csdn.net/weixin_55516868/article/details/128717574
前缀和数组、差分数组、线段树、树状数组均用于处理区间问题,但有不同应用场景
前缀和数组:用于处理 连续多次取区间和 操作的情况,取区间和期间不能对原数组进行区间增减数操作
差分数组:用于处理 多次区间增减数操作,最后读取一次区间和(即修改期间读取不频繁) 操作的情况
线段树:用于处理 多次区间增减数操作,期间多次读取区间和(即修改期间读取频繁) 操作的情况
树状数组:用于处理 多次区间增减数操作,期间多次读取区间和(即修改期间读取频繁) 操作的情况,同线段树的情况、但树状数组更加简单且不支持区间更新,线段树支持区间更新但编码复杂