线段树

线段树

一、线段树简介

1、简单图解及存储结构

线段树用于维护一段区间的性质,包括最值、和、最大公约数等等

线段树

除叶子结点外,是一颗满二叉树 -> 可以用堆来存 -> 可以用一维数组来存

对编号x的节点:

  • 父节点:x/2向下取整,即:x >> 1
  • 左儿子:2*x,即:x << 1
  • 右儿子:2*x+1,即:x << 1 | 1

最坏情况下:假设倒数第2层最多有n个节点,除最后一层外一共有2n-1个节点,最后一层最多有2*n个节点,所以一共最多有4n-1个节点。

2、基本操作及代码(以最大值为例)

//节点:
struct Node
{
    int l, r;
    int v; //区间[l,r]的最大值
}tr[4 * N];
//pushup():单点修改,由子节点更新父节点
void pushup(int u)
{
    tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
//build():初始化线段树
void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if(l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
} 
//modify():单点修改操作
void modify(int u, int x, int v)
{
    if(tr[u].l == x && tr[u].r == x) tr[u].v = v;
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if(x <= mid) modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);
        pushup(u);
    }
}
int query(int u, int l, int r)
{
    //树中节点已经完全包含在区间内
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
    
    int mid = tr[u].l + tr[u].r >> 1;
    int v = 0;
    if(l <= mid) v = query(u << 1, l, r);
    if(r > mid) v = max(v, query(u << 1 | 1, l, r));
    return v;
    //if(r <= mid) return query(u << 1, l, r);
    //else if(l > mid) return query(u << 1 | 1, l, r);
    //else return max(query(u << 1, l, r), query(u << 1 | 1, l, r));
}

//pushdown():区间修改,带懒标记(延迟更新)
//此处以区间和为例
//两个信息:sum(区间和)、add(懒标记、区间每个数需要加的值,意义:所有以当前节点为根节点的子树全部加上add,根节点不加)
void pushdown(int u)
{
    auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    if(root.add)
    {
        left.add += root.add, left.sum += (left.r - left.l + 1) * root.add;
        right.add += root.add, right.sum ++ (right.r - right.l + 1) * root.add;
        root.add = 0;
    }
}
pushup()的位置一般在:build()、modify()的结尾
pushdown()的位置一般在:modify()、query()的开头
    

二、相关题目

1275.最大数

1275.最大数

维护区间最大值的线段树

245.你能回答这些问题吗

245.你能回答这些问题吗

经分析的用线段树维护:区间和、最大前缀和、最大后缀和、最大连续区间和

246.区间最大公约数

246.区间最大公约数

线段树维护:差分数组区间和、区间最大公约数

243.一个简单的整数问题2

243.一个简单的整数问题2

采用带懒标记的线段树解法,实现区间修改,区间查询

247.亚特兰蒂斯

247.亚特兰蒂斯

用线段树维护扫描线,根据该题的特殊性质可推出带懒标记的线段树不需要pushdown操作

让人自闭的题目,裂开。。。。

1277.维护序列

1277.维护序列

带两个懒标记的线段树

原文地址:https://www.cnblogs.com/grain-rain/p/14302624.html