线段树

主要有两个操作:push_up 与 push_down.

push_up

用子节点来算父节点信息,如:sum = l.sum + r.sum

push_down

父节点的修改信息下传到子节点

基本操作

  1. push_up(u)
  2. bulid() 将一段区间初始化为线段树
  3. modify 修改 \(\left \{ \begin{array}{} 单点&\ easy \\ 区间&\ push\_up \ hard \ 懒标记 \end{array} \right.\)
  4. query
  5. push_down

示意:

                       --------------------[1,10]---------------------------
		         /                                              \                 
                 ------[1,5]-------                             --------[6,10]-------
                /                  \                            /                 \ 
           ---[1,3]---         --[4,5]--                   ---[6,8]---        --[9,10]--
            /      \             /   \                     /         \           /   \
       --[1,2]--   -3-         -4-   -5-              --[6,7]--      -8-       -9-  -10-
          /  \                                          /   \
        -1-  -2-                                      -6-   -7-

\(mid=[\frac{l+r}{2}]\)

\([l,mid]\ [r,mid]\)

满二叉树 \(\Longrightarrow\) 用一维数组来存整个数.

编号是x \(\left \{ \begin{array}{} 父节点\ &\frac{x}{2} \ &x\gg 1 \\ 左儿子\ &2x\ &x\ll1 \\ 右儿子\ &2x+1\ &x\ll1|1 \end{array} \right.\)

线段树开空间开4n

bulid

build(int u, int l, int r) {
    tr[u].l = l, tr[u].r = r;
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    push_up(u);
}

query

\([l,R]\): 当前查询的区间.

\([T_L,T_R]\): 树中节点的范围.

证明复杂度为 O(logN):

  1. \([T_L;T_R]\subset [L,R]\) 直接返回.

  2. \([L,R]\land[T_L,T_R]\ne\varnothing\)

    • TL|----mid----|TR
           L|------------|R
          TL <= L <= TR <= R
      

      \(\left \{ \begin{array}{} l>mid \ 只递归右边 \\ l \leq mid \left \{ \begin{array}{} 递归左边\\ 递归右边 \end{array} \right.\end{array} \right.\)

      看似是递归两边,其实右边再递归到下一层就返回了.

    •     TL|----mid----|TR
      L|-----------|R
      

      与上面对称

    •  TL|--------mid--------|TR
             L|---------|R
      

      \(\left \{ \begin{array}{} R \le mid \ 递归左\\ L>mid\ 递归右\\ 其他\ 递归两边\end{array} \right.\)

    • 递归两边只会发生一次,因为一旦分裂,就会变成情况1.

  3. \([L,R]\land[T_L,T_R]=\varnothing\) 不存在

posted @ 2021-04-05 00:22  phr2000  阅读(47)  评论(0编辑  收藏  举报