蓝桥杯学习记录——线段树(from acwing)

线段树是树状数组的变种,用途是在log(n)内查询一个指定区间的咨询(sum、max、min……),树状数组能实现的功能线段树全可以实现,线段树可实现的功能树状数组不一定可以实现。

线段树也是一种二叉搜索树,每个结点存储了一个区间。

线段树的存储利用数组存储,类似于堆

以求区间和为例,线段树做法如下

#include <bits/stdc++.h>
using namespace std;

const int N=10010;
int a[N] //原数组
struct Node  //线段树结点
{
    int l, r;  //区间左端点,右端点
    int sum;   //区间和
}tr[N * 4];  //开4倍的N的空间

void pushup(int u)  //根据两个子节点sum求父节点sum
{
    tr[u].sum = tr[u * 2].sum + tr[u * 2 + 1].sum;
}

void build(int u, int l, int r)  //建立线段树
{
    tr[u].l=l;
    tr[u].r=r;
    if (l == r) tr[u].sum=a[r];
    else
    {
        int mid = ( l + r ) / 2;
        build(u * 2, l, mid); //建立左子树
        build(u * 2 + 1, mid + 1, r); //建立右子树
        pushup(u); //更新此节点
    }
}

int query(int u, int l, int r)   //求区间[l,r]的和
{
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;  //如果tr[u]介于[l,r]之间 
    int mid = ( tr[u].l + tr[u].r )/2 ;
    int sum = 0;
    if (l <= mid) sum = query(u * 2, l, r);  //如果[l,r]包含tr[u]的左子树的部分
    if (r > mid) sum += query(u * 2 + 1, l, r); //如果[l,r]包含tr[u]的右子树的部分
    return sum;
}

void modify(int u, int x, int v)  //修改线段树
{
    if (tr[u].l == tr[u].r) tr[u].sum += v;  //找到叶子结点
    else
    {
        int mid = ( tr[u].l + tr[u].r ) / 2;  
        if (x <= mid) modify(u * 2, x, v);  //如果目标叶子结点在左子树
        else modify(u * 2 + 1, x, v);  //目标叶子结点在右子树
        pushup(u);  //更新此结点的sum
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值