码迷,mamicode.com
首页 > 其他好文 > 详细

线段树

时间:2020-01-22 12:31:09      阅读:55      评论:0      收藏:0      [点我收藏+]

标签:次数   a+b   优化   表示   href   查找   出现   ==   更新   

线段树

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。

使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

建树

int a[maxn];        //题目给出的数组

struct node         //线段树
{
    int l,r,sum,lazy;
}t[maxn*4];

void pushup(int x)
{
    t[x].sum = t[x*2].sum + t[x*2+1].sum;
}

void build(int l,int r,int k)       //第k个节点,左儿子l,右儿子r
{
    int mid = (l+r)/2;
    t[k].l = l,t[k].r = r;
    if(l == r) 
    {
        t[k].sum = a[l];
        return;
    }
    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
    pushup(k);
}

区间更新

void pushdown(int k)
{
    if(t[k].lazy)       //把lazy给左右儿子
    {
        t[k*2].lazy += t[k].lazy;
        t[k*2+1].lazy += t[k].lazy;
        t[k*2].sum += t[k].lazy;
        t[k*2+1].sum += t[k].lazy;
        t[k].lazy = 0;
    }
}

void update(int k,int l,int r,int x)    //l和r区间加上x
{
    if(l <= t[k].l && t[k].r <= r)
    {
        t[k].lazy += x;
        t[k].sum += x;
        return;
    }
    pushdown(k);
    int mid = (t[k].l+t[k].r)/2;
    if(l <= mid) update(k*2,l,r,x);
    if(r > mid) update(k*2+1,l,r,x);
    pushup(k);          //更新父节点
}

区间查询

int query(int k,int l,int r)        //求[l,r]区间和
{
    if(l <= t[k].l && r <= t[k].r) return t[k].sum;
    int res = 0;
    pushdown(k);
    int mid = (t[k].l+t[k].r)/2;
    if(l <= mid) res += query(k*2,l,r);
    if(r > mid) res += query(k*2+1,l,r);
    return res;
}

参考博客:

https://www.cnblogs.com/xenny/p/9801703.html
https://blog.csdn.net/whereisherofrom/article/details/78969718

线段树

标签:次数   a+b   优化   表示   href   查找   出现   ==   更新   

原文地址:https://www.cnblogs.com/hezongdnf/p/12228074.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!