ACM_线段树

本文介绍了线段树这一数据结构,用于区间操作。通过示例展示了如何进行单点更新和区间查询,解释了线段树的基本结构和关键函数,包括push_up、build、update和query,帮助理解线段树如何高效地维护区间最大值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树:
自我理解:把一段区间整体操作的数据结构

整体思路:
这里写图片描述

如图:
假如单点更新 区间查询 现在有10个数
这10个数最开始是 1 2 3 4 5 6 7 8 9 10
查询某个区间的最大值
那么把这些区间按照如下更新
这里写图片描述

现在假如我们查询 2-7的最大值 (当然主观上我们明显知道是7)
我们就可以查询max[2, 2] = 2, max[3, 3] = 3, max[4, 5] = 5, max[6, 7] = 7, 取最大的 = 7;(为什么不直接查询[2, 7]呢, 因为线段树里没有这个区间)
所以我们就知道[2, 7]的最大值是7;

现在假如我们更新其中的一个值:
比如我们把5点的值更新成100;这里写图片描述
每个区间的最大值就成了这样

下次我们再查询max[2, 7]的时候:
max[2, 2] = 2, max[3, 3] = 3, max[4, 5] = 100, max[6, 7] = 7;
取最大的是100;
最大值就等于100;

基本结构:
每个区间都会有1个rt 代表该区间:
然后每个区间的基本结构有3个参数(l, r, rt)分别代表这个区间的左端点, 右端点, 区间的下标)
首先 整个区间的下标用1表示
每个区间的中点m = l + r >> 1;
然后每个父节点有一个左儿子:(l, m, rt << 1)一个右儿子(m+1, r, rt << 1 | 1)如此建树

几个函数:
void push_up(向上推)
void push_donw(向下推, 当然这个题不需要这个功能, 求区间和的时候需要)
void build(建树)
void update(更新某些值)
int query(查询符合要求的值)

  1. void push_up

    void push_up(int rt){
        h[rt] = max(h[rt << 1], h[rt << 1 | 1]);
    }

    h代表最大值 [l, r]的最大值等于它左儿子的最大值和右儿子的最大值里大的那个;

  2. build

    void build(int l, int r, int rt){
        if(l == r){
            scanf("%d", &h[rt]);
            return;
        }
        int m = l + r >> 1;
            build(lson);
            build(rson);
            push_up(rt);
        }

当不断向下搜索知道l = r的时候, 那么这个区间就只有1个值, 那么这个值一定就是最大值, 读入它;
否则 我们把它的左边儿子建立了, 右边儿子建立了, 再从它左儿子和右儿子两个最大值中取大的那个;

这里写图片描述

建树后就变成了上图, 其中黑色底字是区间, 红色的字是区间的最大值, 绿色的字是区间的下标

  1. void update

    void update(int x, int y, int l, int r, int rt){
        if(l == r){
            h[rt] = max(h[rt], y);
            return;
        }
        int m = l + r >> 1;
        if(x <= m) update(x, y, lson);
        else update(x, y, rson);
        push_up(rt);
    }

    如果l = r 说明该区间只有1个值了, 那么更新到这里把需要更新的值读入就OK了, 该值一定是最大值
    否则就继续向下更新 并在两个儿子的最大值中取最大的那个

    比如更新把5更新成100
    按照天蓝色的线更新:注意一下路上区间的最大值变化(红色的字)

这里写图片描述

  1. int query
int query(int L, int R, int l, int r, int rt){
    if(L <= l && r <= R) return h[rt];
    int ret = -INF;
    int m = l + r >> 1;
    if(L <= m) ret = max(ret, query(L, R, lson));
    if(R > m) ret = max(ret, query(L, R, rson));
    return ret;
}

查询函数: if(L <= l && r <= R)说明查询的区间已经包含到了向下询问的空间了, 直接返回这个区间的最大值就OK了
否则就返回它的左儿子和右儿子的最大值中较大的那个就OK了;
这里写图片描述
顺着天蓝色的线向下找, 找到这些区间的最大值并返回就OK

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值