ACM_线段树

来源:互联网 发布:广数g72内孔编程实例 编辑:程序博客网 时间:2024/06/05 14:12

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

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

如图:
假如单点更新 区间查询 现在有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

0 0