• 线段树(一):点修改


        动态范围最小值问题。给出一个有$n$个元素的数组$A_1, A_2, ..., A_n$,你的任务是设计一个数据结构,支持以下两种操作:

    • $Update(x, v)$:把$A_x$修改为$v$
    • $Query(L, R)$:计算$min { A_L, A_{L+1},...,A_R } $

        如果还是使用$Sparse-Table$算法,每次$Update$操作都需要重新计算$d$数组,时间无法承受。为了解决这个问题,这里介绍一种灵活的数据结构:线段树(segment tree).

        在查询时,我们从根节点开始自顶向下找到待查询线段的左边界和右边界,则“夹在中间”的所有叶子结点不重复不遗漏地覆盖了整个待查询线段。从图中不发现,树的左右各有一条“主线”,虽然各自分叉,但每层最多只有两个结点向下延伸,因此“查询边界”结点个数不超过$2h$个,其中$h$是线段树的最大层编号。这实际上是把待查询线段分成了不超过$2h$个不相交线段的并。在后文中,凡是遇到这样的区间分解,就把分解得到的各个区间叫做边界区间,因为它们对应于分解过程的递归边界。

        如何更新线段树呢?显然需要更新线段$[i, i]$对应的结点,然后还需要更新它的所有祖先结点。不发现,其他的值并没有改变。

        以下是代码。这里的$o$是当前结点编号,$L$和$R$是当前结点的左右端点。查询时,全局变量$ql$和$qr$分别代表查询区间的左右端点;修改时,全局变量$p$和$v$分别代表修改点位置和修改后的值。

     1 const int INF = 0x3f3f3f3f;
     2 const int maxn = 100000 + 10;
     3 int minv[maxn << 2];
     4 int n, a[maxn];
     5 
     6 void build(int o, int L, int R)
     7 {
     8     int M = L + (R-L) / 2;
     9     if(L == R)  minv[o] = a[L];
    10     else
    11     {
    12         build(2*o, L, M);
    13         build(2*o+1, M+1, R);
    14         minv[o] = min(minv[2*o], minv[2*o+1]);
    15     }
    16 }
    17 
    18 int ql, qr;    //查询[ql, qr]中的最小值
    19 int query(int o,int L,int R)
    20 {
    21     int M = L + (R - L) / 2;
    22     int ans = INF;
    23     if(ql <= L && R <= qr)  return minv[o];
    24     if(ql <= M)  ans = min(ans, query(2*o, L, M));
    25     if(qr > M)  ans = min(ans, query(2*o+1, M+1, R));
    26     return ans;
    27 }
    28 
    29 int P, v;  //修改A[p]=v
    30 void update(int o, int L, int R)
    31 {
    32     int M = L + (R-L)/2;
    33     if(L == R)  minv[o] = v;  //更新叶子结点
    34     else
    35     {
    36         if(P <= M)  update(2*o, L ,M);
    37         else  update(2*o+1, M+1, R);
    38         minv[o] = min(minv[2*o], minv[2*o+1]);  //更新非叶子结点
    39     }
    40 }

        最后叙述一下建树过程。一种方法是每读入一个元素$x$后执行修改操作$A[i]=x$,则时间复杂度为$O(nlogn)$。其实只需要事先设置好每个结点的值,自底向上递推即可(也可以写成递归)。每个结点仅计算了一次,因此为时间复杂度$O(n)$。

  • 相关阅读:
    ASP.NET DropDownList 控件绑定数据
    Linux图形界面与命令行界面切换
    Linux性能分析
    UTF虚拟对象
    UFT场景恢复
    UFT参数化
    UFT检查点
    UFT三种录制方式
    UFT基本操作
    UFT安装目录简单介绍
  • 原文地址:https://www.cnblogs.com/lfri/p/11094711.html
Copyright © 2020-2023  润新知