Arrays 向范围内的数组元素添加特定值的快速算法?

Arrays 向范围内的数组元素添加特定值的快速算法?,arrays,algorithm,segment-tree,Arrays,Algorithm,Segment Tree,在范围更新问题中,我想向范围中的数组元素添加一个值。可以假定数组(或某些数据结构)已排序 一个简单的算法是通过开始元素循环到结束元素,并为每个元素添加一个值v 但在最坏的情况下,当范围从第一个元素到最后一个元素时,这需要O(n)时间。有没有更快的方法?我应该使用段树吗?如果数组真的是一个c样式的数组(不一定是排序的),而不是一个已经隐式地将其顺序包含在其结构中的树型数据结构,那么O(n)是您能得到的最好的结果 还有其他数据结构(允许更快查找的各种类型的树。但是,将未排序的数组转换为这些结构之一总

在范围更新问题中,我想向范围中的数组元素添加一个值。可以假定数组(或某些数据结构)已排序

一个简单的算法是通过开始元素循环到结束元素,并为每个元素添加一个值v


但在最坏的情况下,当范围从第一个元素到最后一个元素时,这需要O(n)时间。有没有更快的方法?我应该使用段树吗?

如果数组真的是一个c样式的数组(不一定是排序的),而不是一个已经隐式地将其顺序包含在其结构中的树型数据结构,那么O(n)是您能得到的最好的结果


还有其他数据结构(允许更快查找的各种类型的树。但是,将未排序的数组转换为这些结构之一总是比O(n)更糟糕。

如果数组已排序,则可以快速搜索(例如,使用二进制搜索)任何单个元素都属于您的范围。此后,将您的增量值添加到入口点之前和之后的元素

例如,let数组包含int。 因此,代码如下所示:

int *p;
// try to fill array from begin to element range_max
if(your_array[0] >= range_min) {
  for(p = your_array; p < your_array + elems_qty; p++)
    if(*p <= range_max)
      *p += delta;
    else 
      break;
  return; // head of array filled
}

// try to fill array from end to element range_min
if(your_array[elms_qty - 1] <= range_max) {
  for(p = your_array + elms_qty - 1; p >= your_array; p--)
    if(*p >= range_min)
      *p += delta;
    else 
      break;
  return; // tail of array filled
}

// There is range somewhere inside array

int avg_element = (range_min + range_max) / 2;

int *avg_ptr = bsearch(&avg_element, your_array, elems_qty, sizeof(int), int_comparator);

for(p = avg_ptr; *p >= range_min; p--)
  *p += delta;

for(p = avg_ptr; *p <= range_max; p++)
  *p += delta;
int*p;
//尝试从开始到元素范围_max填充数组
如果(你的数组[0]>=范围最小值){
对于(p=您的数组;p<您的数组+元素数量;p++)
如果(*p=范围\最小值)
*p+=δ;
其他的
打破
return;//数组尾部已填充
}
//数组中的某个地方有射程
int avg_元素=(最小范围+最大范围)/2;
int*avg_ptr=b搜索(&avg_元素、数组、元素数量、大小(int)、int_比较器);
对于(p=avg_ptr;*p>=range_min;p--)
*p+=δ;

对于(p=avg_ptr;*p如果速度很重要,并且您仅在闭合范围内操作并添加每个时间常量值,您可以创建“修改队列”,在其中放置修改序列,由
定义(起始索引、结束索引、增量)
,保持数组本身不受影响。实际处理可能在活动最少的时候执行


这将使修改以保证的O(1)运行,但随机读取成本将增加到O(K),其中K是队列的大小(后续刷新之间的平均修改次数)。如果数组很大,范围很广,但修改并不经常发生,而且必须很快返回,那么这种方法可能会成功。

您可以使用。它比段树更容易实现。(它被称为树,但实际上是作为数组实现的,就像二进制堆一样).

如果数组已排序,则可以使用二进制搜索来定位范围是的,数组已排序,但这是什么意思?除非对范围有一些限制,否则这是定义O(n)。我刚刚读到关于段树中的延迟传播。我认为这可以解决问题。使用段树是一种过分的做法。Fenwick树特别适合此任务,并且更易于实现。因此我实际上可以自由决定树数据结构,因此我可以使用具有延迟传播的段树来添加值。谢谢s!对于此任务,与数组上的二进制搜索相比,树结构本身并没有给您带来性能优势。如果您可以修改搜索以在同一搜索中定位最小值和最大值,则会有轻微的优势。是的,树结构(段树、Fenwick树)如果您需要执行多个查询或结构处于联机状态,则可以提供性能优势。如果您还通过设置
aux[start]=delta
aux[end]=-delta
将修改存储在辅助size-n数组中,并强制每个sqrt(n)次访问(读或写)要执行刷新,则队列始终为O(sqrt(n)),您将得到摊销O(sqrt(n))任何读写序列的每访问边界。仍然不如使用段树或Fenwick树好,但很有趣!@j_random_hacker是的,有很多方法可以修改。存储修改的范围树是我认为最好的方法。@j_random_hacker我给出这个答案主要是为了反驳评论,并显示一种相反的方法:快速更新e、 慢读vs慢更新,快读。我的目的是要说明问题不仅在于更新的成本,更在于实际使用场景。