线段树

线段树

蓝某杯省赛比赛结束后,倒数第二题是线段树,但是我没想到怎么建树。时隔几个月,蓝某杯国赛结束后,这题线段树可以做,但是我没写出来。(这是我一个朋友[doge])

简介

​ 线段树作为一个高级数据结构,而且是高级数据结构里面比较简单的一种,蓝某杯最喜欢拿他做压轴题。而压轴题的分一般都是20~25分,所以做出来 = 拿奖。相信你已经迫不及待想知道这个让算法大佬都又爱又恨的数据结构长什么样了吧。

  1. 线段树是一颗二叉搜索树,一个结点储存的信息是一个区间的信息,一般用一维数组来表示线段树。
  2. 每个父结点有两个子节点,将父节点的区间成两个区间(一般都是从中间分),子节点分别存储这两个区间的数据。
  3. 叶子节点的区间大小为1,存储的是单个数据。
  4. 线段树的查询复杂度是O(logn),空间复杂度为O(n<<3) = O(8*n) ≈ O(n),适合处理频繁区间查询的任务。
5.1二叉树的一般结构

​ 假设有个长度为8的数组。不难理解,8~15 存储的是这个数组的元素。那么1~7 存储的是什么呢?这1~7存储什么根据你的需求来定,你可以存储这个区间的最大值、最小值、区间和......

代码实现

下面以存储区间和来建一个线段树。

获得子树索引

设某结点某结点在数组中索引为i,结点的左右子树的索引分别为 2*i 和 2*i+1。可以自行带一下公式验证一下。

5.2.1 5.2.2
long long ls(long long x) { return x<<1; } // << 左移运算符,相当于*2
long long rs(long long x) { return x<<1|1; } // | 按位或运算,可以理解为+1,
建树
/**
 * 建树是一个递归的过程,从根节点开始。 build(1,1,n);
 * p: 当前的结点索引
 * pl: 当前节点区间左端 (point left)
 * pr: 当前节点区间右端 (point right)
 */
void build(long long p,long long pl,long long pr)
{
    tag[p] = 0;
    // 长度为1的结点,最底层 
    if(pl == pr) 
    {
        tree[p] = arr[pl];
        return ;
    }
    // 分治
    long long mid = pl + pr >> 1;
    build(ls(p),pl,mid);
    build(rs(p),mid+1,pr);
    // 合并结果
    tree[p] = tree[ls(p)] + tree[rs(p)];
}
查询

如果我要查询2~6 的和,我只需要查询节点953的值,将这些值加起来就是2~6 的和了。那么问题来了,我们怎么知道要查询节点953呢?不难看出,自上而下来查询,如果当前节点的区间被要查询的区间完全覆盖了,那么当前节点就是我们要找的结点,反之则需要继续往下查询。大家可以根据下面的图来模拟一下。

5.2.1
/**
 * L: 要查询区间的左端
 * R: 要查询区间的右端
 * p: 当前的结点索引
 * pl: 当前节点区间左端
 * pr: 当前节点区间右端
 */
long long query(long long L,long long R, long long p,long long pl,long long pr)
{
    // 如果要查询的区间能覆盖当前节点的区间,返回当前节点的值
    if(L<=pl && pr<=R) return tree[p];
    // 如果不能覆盖,则继续往下查询
    long long res=0;
    long long mid = pl + pr >> 1;
    if(L<=mid) res += query(L,R,ls(p),pl,mid);
    if(mid<R) res += query(L,R,rs(p),mid+1,pr);
    // 返回查询结果
    return res;
}

总结

​ 恭喜你看完了,你对线段树这个数据结构有了初步的了解,知道了他的建树和查询的过程。然而这些只是线段树的冰山一角,后面还有线段树的区间修改、离散化、Lazy_tag、空间优化、多维推广、可持久化、非递归形式、子树收缩......蓝某杯不会考太难的线段树,但是肯定也不会简单,不然也不会有开篇的那位算法大佬的哀嚎了。(我是蒟蒻,我连蓝某杯有线段树的题目都不知道......)

练练手

https://www.luogu.com.cn/problem/P3372

https://www.luogu.com.cn/problem/P3373

https://www.luogu.com.cn/problem/P6242

https://blog.csdn.net/m0_49924838/article/details/122840892

posted @ 2022-09-17 20:51  小兜兜me  阅读(44)  评论(0编辑  收藏  举报