线段树思想

什么是线段树?
当你要面临一个问题需要反复区间修改以及查询区间内的某个结果(如区间和、区间最值),如果用朴素的暴力修改与查询时间复杂度会非常的高,这时利用线段树或者树状数组来维护就可以以O(log)级别的时间复杂度来得到结果,这就是线段树。

如以下用长度为10的数组,来建立线段树,维护区间和,单点修改操作.
在这里插入图片描述
用线段树构造的逻辑图如下所示,以数组下标左右两端为长度,进行划分,每次分两段,直至叶子节点(L == R)不能分为止。
在这里插入图片描述
由上图可知,每个叶子节点 L == R 对应原数组一个对应值a[L] 或 a[R]。每个节点均对应原数组a区间[L,R],在每个节点处留一个sum值,该sum值就是区间[L,R]的和.
观察上述线段树的逻辑结构,可知是一颗平衡树,是一颗完全二叉树。所以父节点与左右儿子之间的关系可以用一个一维数组表示,当前节点为p,左儿子为p2,右儿子为p2+1。

所以在用线段树维护区间时,需要先建树,在已经建成的树上进行修改与查询
线段树的一般数据结构

struct STree
{
    int l, r;// 当前节点的左端点、右端点
    int dat, sum;//sum区间和值
}t[SIZE * 4];

int a[SIZE];//原数组

故线段树有三个基本的操作:
1.建树
step1: 先存储当前节点p的左端点值l与右端点值r.
step2: 判断左端点与右端点是否相等 相等 把原数组的对应下标值赋给叶子节点值返回
step3: 用分治的思想从当前左右端点值之和取中点进行划分
step4:递归左儿子节点,区间缩短至[L,mid]
step5:递归右儿子节点,区间缩短至[mid+1,R]
重复上述步骤即可

void build(int p, int l, int r)
{
    t[p].l = l, t[p].r = r;
    if(l == r){
        t[p].sum = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(p*2,l , mid);
    build(p*2+1, mid+1, r);

    t[p].sum = t[p*2].sum + t[p*2+1].sum;
}

用法: build(1,1,10);//建立[1,10]区间的线段树

2.单点修改原数组a[x]值
从根节点开始递归,找到左右端点值等于x的值,即找到对应修改x的值在叶子节点的位置,类似搜索树的方式进行探索.

void change(int p,int x,int v)
{
    if(t[p].l == t[p].r){
        t[p].sum = v;
        return;
    }
    int mid = (t[p].l + t[p].r) >> 1;
    if(x <= mid) change(p*2, x, v);
    else  change(p*2+1, x, v);

    t[p].sum = t[p*2].sum + t[p*2+1].sum;
}

使用方法: change(1, x, v);//x为下标值,v为修改值

3.查询区间[L,R]的区间和

有二种情况:
t[p].l t[p].r 为当前树上节点
情况一:当[L,R] 区间 包含了 当前树上的节点所表示的区间和时,直接返回
情况二:不包含时,mid为当前节点区间的中点,L<=mid,满足查询[L,mid]剩余和
再R>mid,查找满足[mid+1,R]剩余和,返回次区间即可.

int ask(int p, int l, int r)
{
    if(l >= t[p].l && t[p].r >= r){
        return t[p].sum;
    }
    int mid = (t[p].l + t[p].r) >> 1;
    int val = 0;
    if(l <= mid) val+=(p*2,l,r);
    if(r > mid) val +=(p*2+1,l,r);
    return val;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值