线段树学习总结

队伍分好后,我负责数据结构部分。。。。 以后要狂补数据结构了,不能再做水题找存在感了。
今天总结一下线段树 以后长期更新题型。。
**

part 1 线段树是是什么?

**

线段树是一种可以方便维护数列的数据结构。 更新和查找都可以在log(n)的复杂度内完成。 经(我)证(不)明(会)其最差空间复杂度为4*n。记住就好。
线段树可以看做维护线段的树

part 2 线段树如何的结构是什么?

首先,线段树可以看做一颗完全二叉树
这里写图片描述
完全二叉树有什么用呢? 我们发(百)现(度) 二叉树符合二进制思想,我们可以从一开始从上往下 从左至右编号 如下图
这里写图片描述
这就很完美,我们可以在log(n)的时间内查找到我们想要查找的任意一个点。

**

part 3 线段树如何建立?

**

下面给出一个看(比)得(较)懂(长)的模板。
线段树的建立 build() 函数

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fuck(x) cout<<x<<endl
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
const int MAX=55555;
int n;
void pushup(int rt)
{
    sum[rt]=(sum[rt<<1|1]+sum[rt<<1|1]); //  递归后把子节点的信息传给父节点
}
void build(int l,int r,int rt)
{
    sum[rt]=xxxx;// 初始化节点
    // 以下为固定代码
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

区间更新pushdown函数,用于区间更新 add数组为懒惰标记数组

//以下代码为区间加减代码
void pushdown(int rt)
{
    if(add[rt]!=-1)
    {
        sum[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        add[rt<<1]+=add[rt];
        add[rt]=-1;
    }
}

涉及区间合并 求最长区间或符合条件的连续区间一般这么写

class node
{
public:
    int llen,rlen,tlen;
};  
// 我们将sum数组由int型换成自定义类 
//llen表示该节点所代表区间以左端开始最长合法区间 
//rlen为该节点所代表的区间以右端结束的最长合法区间
//tlen为该区间里最长合法区间。
node sum[MAX<<2];
int a[MAX];
void pushup(int l,int r,int rt)
{
    int m=(l+r)>>1;
    sum[rt].tlen=max(max(sum[rt<<1].tlen,sum[rt<<1|1].tlen),sum[rt<<1|1].llen+sum[rt<<1].rlen);
    sum[rt].llen=sum[rt<<1].llen; if(sum[rt].llen==(m-l+1)) sum[rt].llen+=sum[rt<<1|1].llen;
    sum[rt].rlen=sum[rt<<1|1].rlen; if(sum[rt].rlen==(r-m)) sum[rt].rlen+=sum[rt<<1].rlen;
}
void build(int l,int r,int rt)
{
    sum[rt].llen=sum[rt].rlen=sum[rt].tlen=(r-l+1);
    if(l==r) return;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(l,r,rt);
}
void update(int p,bool flag,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt].llen=sum[rt].rlen=sum[rt].tlen=flag;
        return;
    }
    int m=(l+r)>>1;
    if(p>m) update(p,flag,rson);
    else if(p<=m) update(p,flag,lson);
    pushup(l,r,rt);
}
int ans=-1;
int query(int p,int l,int r,int rt)
{
    if(l==r)
        return ans=sum[rt].tlen;
    int m=(l+r)>>1;
    if(p<=m)
    {
        if(m-sum[rt<<1].rlen<=p) return query(p,lson)+sum[rt<<1|1].llen;
        else return query(p,lson);
    }
    else
    {
        if(m+sum[rt<<1|1].llen>=p) return query(p,rson)+sum[rt<<1].rlen;
        else return query(p,rson);
    }
}
// 网上都有详解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值