线段树学习笔记

前排放各种大佬对于线段树文章:
luogu大佬_皎月半洒花

y1-Day3)

一、基本概念

什么是线段树?
  • 线段树是一种二叉搜索树,与其他树不一样的是:正常的树节点信息是一个,而线段树是一段,所以它每个节点记录左端点、右端点、线段的信息。
优点

当我们需要对【1,n】范围内的任意区间【l,r】进行修改或求区间和,暴力复杂度很高,所以我们需要将每个区间都提前保存下来,需要改哪些就该哪些。

  • 使用线段树可以快速的查找某一个节点在线段中出现的次数,查找时间复杂度为O(logN)。而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界。
储存
  • 每个节点以结构体的方式存储,结构体包含以下几个信息:
    (1) 区间左端点、右端点
    (2)这个区间要维护的信息
    (3)lazy tag(懒标记)

  • 基本思想:二分

  • 基本形式:
    (1)每个节点的左孩子区间为[l,mid],右孩子为[mid+1,r]
    (2)对于结点k,左孩子为2k,右孩子为2k+1

二、基本操作

1、构建
  • 思路
    ①确定每次二分到的节点的左右端点、左右范围。
    ②叶子节点,存储要维护的信息。
    ③状态合并,计算父节点的区间和。
struct node//结构体
{
	int l,r,sum,mark;//同上储存
}xds[400001];//记得开4倍!!!线段树xds
/**
用结构体存储若要访问儿子或父亲很方便
直接xds[p<<1] xds[p<<1|1] xdse[p>>1]
*/
void build(int l, int r, int rt)//l,r表示当前节点区间,rt表示当前节点编号
{
    xds[rt].l=l;
    xds[rt].r=r;
    if(l==r){//到达叶子节点
        scanf("%d", &xds[rt].sum);
        return;
    }
    int m=(l+r)/2;//二分
    build(ls);//建立左子树
    build(rs);//建立右子树
    xds[rt].sum=xds[rt<<1].sum+xds[rt<<1|1].sum;
    //状态合并,此结点的sum=两个孩子的sum之和 
}
下传
void down(int rt)//标记下传 
{
    xds[rt<<1].mark+=xds[rt].mark;
    xds[rt<<1|1].mark+=xds[rt].mark;
    xds[rt<<1].w+=xds[rt].mark*(xds[rt<<1].r-xds[rt<<1].l+1);
    xds[rt<<1|1].w+= xds[rt].f*xds[rt<<2|1].r-xds[rt<<2+1].l+1);
    tree[rt].f = 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值