我正在从数据数组中实现分段树,我还想在更新数据范围时保持树的最大/最小值。以下是我在本教程http://p--np.blogspot.com/2011/07/segment-tree.html之后的初步方法。
不幸的是它根本不起作用,逻辑对我来说很有意义,但我对b
和e
有点困惑,我想这是data
数组的范围?或者它是树的实际范围?根据我的理解,max_segment_tree[1]
应该保留范围max
的{{1}},[1, MAX_RANGE]
应该保持范围min_segment_tree[1]
的{{1}}。
min
修改 添加测试用例:
[1, MAX_RANGE]
答案 0 :(得分:5)
您需要单独存储每个间隔的最大值/最小值,以及添加了哪些值(只是它们的总和)。以下是它可能出错的方式:
假设我们正在为数组[5,1,3,7]构建一个树(我只在这里显示最小树)。树看起来像这样:
1
1 3
5 1 3 7
然后我们在整个区间加1。树看起来像这样:
2
1 3
5 1 3 7
因为传播已在第一个节点上停止,因为更新的时间间隔完全覆盖了它。
然后在范围[0-1]中加1。此范围不包括第一个节点的整个间隔,因此我们更新子节点,然后将整个间隔的min(即第一个节点的值)设置为节点2和3的min。是结果树:
2
2 3
5 1 3 7
这是错误的地方 - 数组中没有元素2,但是树声称整个数组的最小值是2.这是因为树的较低级别实际上从未得到信息它们的值已经增加 - 第二个节点没有意识到它的值不是[5,1]而是[6,2]。
为了使其正常工作,您可以添加第三个数组,以保留已添加到整个时间间隔的值 - 例如int added_to_interval[3 * MAX_RANGE + 1];
。然后,当您更新整个时间间隔(i <= b && j >= e
)的情况时,您还必须使用added_to_interval[position]
增加value
。此外,当上升树以从子项的值更新节点时,您还必须添加已添加到整个时间间隔的节点(例如max_segment_tree[position] = max(max_segment_tree[position * 2], max_segment_tree[position * 2 + 1]) + added_to_interval[position];
)。
修改强>
以下是对其进行更改的代码:
if (i <= b && j >= e) {
max_segment_tree[position] += value;
min_segment_tree[position] += value;
added_to_interval[position] += value;
return;
}
...
update_tree(position * 2 , b , (b + e) / 2 , i, j, value);
update_tree(position * 2 + 1 , (b + e) / 2 + 1 , e , i, j, value);
max_segment_tree[position] = max(max_segment_tree[position * 2], max_segment_tree[position * 2 + 1]) + added_to_interval[position];
min_segment_tree[position] = min(min_segment_tree[position * 2], min_segment_tree[position * 2 + 1]) + added_to_interval[position];
我没有对它进行过广泛的测试 - 我将它留给你,但我尝试了一些似乎正常工作的例子。
另外,我认为数组中不需要3 * MAX_RANGE + 1个元素 - 2 * MAX_RANGE或类似的元素就足够了。
答案 1 :(得分:3)
[b,e] 是范围,由 * _ segment_tree [position] 覆盖, [i,j] 是当前查询范围。
关于范围存储:
* _ segment_tree [1] 保存整个数据数组的 max / min - 它是树的根,因为基于数组的二叉树必须从索引1 即可。这是因为树的 n 第一节点的子节点编号为 2 * n 且 2 * n + 1 , 0 < / strong>不能用作 n ,因为在这种情况下 2 * n = n 。因此,如果 * _ segment_tree [k] 保持数据[b,e] 的最小值/最大值,则 * segment_tree [2 * k] 成立数据的最小值/最大值[b,(b + e)/ 2] 和 * segment_tree [2 * k + 1] - 数据[(b +) e)/ 2 + 1,e] - 您可以在代码中看到这些标记。