Segment Tree 线段树 | 数据结构分析及例题

线段树是一种 二叉树存储结构

如果要求出一个时常更新的序列的一个连续子序列和/极值,我们可以用二叉树。

like?

一座大楼有n个停车场,加入你要做调查,统计从l-r号停车场每个时段的车辆数,只要用lg(N)个时间代价就可以做到实时更新(N为车辆数)。

具体实现可以参看以下博文:

线段树(segment tree),看这一篇就够了


数据结构

线段树的结构可以这样解释:
单个数组元素生成底层叶子,一个根节点管着两个子节点,根的值根据需要修改(可以是和、极值等),然后向上迭代,这样上面的根所包含的区间就是由子树组成的序列闭区间[l,r]

更新操作 类似于堆调整的处理方法,从叶子顺着到根,进行数据的更新,花费代价为O(lg(N))

一般空间大小开原数据的2-4倍哦~

一般有数组自定义结点两种写法。


例题

简述:

敌方有n个兵营,你作为侦查员要实时监测兵营人数,对几个连续的兵营人数求和

总共有Add/Sub/Query增删查(区间)三种操作

本题采用数组
附上关键代码,以及自己的一些注释

buildTree

//建树,只需要两个点,一个起点,一个终点
    if(left == right)
    {
        //输入兵营里的人数
        scanf("%d", &segment[root]);
        return;
    }
    int mid = (left + right) / 2;
    buildTree(root * 2, left, mid);//建左树
    buildTree(root * 2 + 1, mid + 1, right);//建右数
    //调整它的上面节点的值
    pushUp(root);//**注意这里的顺序,子节点的值有了,才能对根赋值

update
注意pushUp的位置

    if (left == right)
    {
        segment[root] += add_num;
        return;//**记得要return
    }
    int mid = (left + right) / 2;
    if (pos <= mid)
        update(root * 2, pos, add_num, left, mid);//更新节点在左区间
    else
        update(root * 2 + 1, pos, add_num, mid + 1, right);//更新节点在左区间
    //向上调整
    pushUp(root);

getSum
注意三个分支
第三个分支需要再分为两个区间(即两个子树)内进行求和

    //如果在当前节点的右半个区间内
    if(left > mid)
    {
        res += getSum(root * 2 + 1, left, right, mid + 1, R);
    }
    //如果在当前查询区间段的左半个区间内
    else if(right <= mid)
    {
        res += getSum(root * 2, left, right, L, mid);
    }
    //一个在左半边,一个在右半边
    else
    {
        res += getSum(root * 2, left, mid, L, mid);//**注意理解这两句话
        res += getSum(root * 2 + 1, mid + 1, right, mid + 1, R);//这里 right 和 R 的位置是对称的
    }

第二种结点数据结构形式…

你可能感兴趣的:(算法Algo,算法)