蒟蒻奉上一篇线段树学习笔记(ssfd)。

曾经有个ACM Au选手尝试往我愚笨的脑袋死命数据结构,最后还是我自己一年脑容量略大之后才真正学进去的。(羞愧)

先借个图

如图所示,线段树有以下性质:

1.线段树本质是棵二叉树.

2.线段树每个节点是代表一个区间l~r,而每个节点的两个儿子是将父节点的区间一分为二,分别l~mid,mid+1~r。

3.叶子节点l等于r

综上所述,我们可以按二叉树的建树方法,若节点编号为th,则节点的左儿子编号为th2,而右儿子记为th2+1。

这里有个小技巧(算不上技巧的技巧)

#define lson th<<1
#define rson th<<1|1
//又是那句话,不是装X,真的会快点的QWQ!!!

现有一个序列A1~N,要将线段树构建以来维护,这里我们用递归建树

#define lson th<<1
#define rson th<<1|1
#define maxn 1000005

int a[maxn];
int tree[maxn*4];//手动画一棵树,发现是会达到4*n的级别的

void build(int l,int r,int th)
{
    if(l==r)//当为叶子节点时
    {
        tree[l]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,lson);//构建左节点
    build(mid+1,r,rson);//构建右节点
    pushup(th);//从两个子节点更新
}

上述类似于一个建树的模板,根据我们的维护的对象的需要,我们可以将其进行扩展。

如维护最小值和最大值

#define lson th<<1
#define rson th<<1|1
#define maxn 1000005

int a[maxn];
int tree[maxn*4];
int mi[maxn*4];
int ma[maxn*4];

void pushup(int th)
{
    mi[th]=min(mi[lson],mi[rson]);
    ma[th]=max(ma[lson],ma[rson]);
    //从两个儿子进行更新
}
void build(int l,int r,int th)
{
    if(l==r)//当为叶子节点时
    {
        tree[l]=mi[l]=ma[l]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,lson);//构建左节点
    build(mid+1,r,rson);//构建右节点
    pushup(th);//从两个子节点更新
}

今天晚上就先写到这吧。

23:20

12.7

版权声明:本文为atlinux原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/atlinux/p/Segment-Tree-Learning-Notes1.html