zoukankan      html  css  js  c++  java
  • 数据结构--线段树

    线段树

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

    对于线段树中的每一个非叶子节点[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 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);
        t[k].sum = t[k*2].sum + t[k*2+1].sum;
    }
    

    区间更新

    void pushdown(int k)        //把lazy值传递下去
    {
        if(t[k].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].r - t[k*2].l + 1);
            t[k*2+1].sum += t[k].lazy*(t[k*2+1].r - t[k*2+1].l + 1);
            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 * (t[k].r - t[k].l + 1); 
            return;
        }
        pushdown(k);
        if(t[k*2].r >= l) update(k*2,l,r,x);
        if(t[k*2+1].l <= r) update(k*2+1,l,r,x);
        t[k].sum = t[k*2].sum + t[k*2+1].sum;
    }
    

    区间查询

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

    区间赋值

    有些时候需要把区间整体赋为某个值,我们可以利用lazy保存区间真正的值,然后至上而下更新,把+=改为=

    void pushdown(int k)
    {
        if(t[k].lazy != -1)
        {
            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].r - t[k*2].l + 1);
            t[k*2+1].sum = t[k].lazy*(t[k*2+1].r - t[k*2+1].l + 1);
            t[k].lazy = -1;
        }
    }
    
    void update(int k,int l,int r,int x)
    {   
        if(l > r) return;
        if(l <= t[k].l && t[k].r <= r)
        {
            t[k].sum = x*(t[k].r-t[k].l+1);
            t[k].lazy = x;
            return;
        }
        pushdown(k);
        if(t[k*2].r >= l) update(k*2,l,r,x);
        if(t[k*2+1].l <= r) update(k*2+1,l,r,x);
        pushup(k);
    }
    

    模板

    struct tree_node
    {
        int l,r,sum,lazy;
    };
    
    struct segtree
    {
        tree_node t[maxn*4];
        void pushup(int k)
        {
            t[k].sum = (t[k*2].sum+t[k*2+1].sum)%M;
        }
        void pushdown(int k)
        {
            if(t[k].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].r - t[k*2].l + 1);
                t[k*2+1].sum += t[k].lazy*(t[k*2+1].r - t[k*2+1].l + 1);
                t[k].lazy = 0;
            }
        }
        void build(int k,int l,int r)
        {
            t[k].l = l,t[k].r = r;
            if(l == r)
            {
                t[k].sum = 0;           //初始值
                return;
            }
            int mid = (l+r)/2;
            build(k*2,l,mid);
            build(k*2+1,mid+1,r);
            pushup(k);
        }
        void update(int k,int l,int r,int x)
        {   
            if(l > r) return;
            if(l <= t[k].l && t[k].r <= r)
            {
                t[k].sum = (t[k].sum +  x*(t[k].r-t[k].l+1))%M;
                t[k].lazy = (t[k].lazy + x)%M;
                return;
            }
            pushdown(k);
            if(t[k*2].r >= l) update(k*2,l,r,x);
            if(t[k*2+1].l <= r) update(k*2+1,l,r,x);
            pushup(k);
        }
        int query(int k,int l,int r)
        {
            if(l > r) return 0;
            if(l <= t[k].l && t[k].r <= r)
            {
                return t[k].sum;
            }
            int res = 0;
            pushdown(k);
            if(t[k*2].r >= l) res = (res + query(k*2,l,r))%M;
            if(t[k*2+1].l <= r) res = (res + query(k*2+1,l,r))%M;
            return res;
        }
    }st;
    

    参考博客:

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

  • 相关阅读:
    1.14验证码 彩票
    String代码示例
    1.13作业
    控制台输入人数和分数 自动判断最高分最低分
    对矩阵进行转置运算
    16、输入三角形的三个边,求其面积
    02、
    15、判断字符串是否回文——字符串
    14、求出最大元素的下标及地址值——数组
    13、字符串在指定的地方以及元素个数实行逆置——字符串
  • 原文地址:https://www.cnblogs.com/hezongdnf/p/12228074.html
Copyright © 2011-2022 走看看