• 线段树个人理解及模板


    一.线段树的相关定义及用途

     (1)线段树的定义

        线段树是一种可以加快对区间进行更新以及查询的一种树状结构,类似于将一个区间的及其子区间的相关信息存储在一颗二叉树中。

        (2)线段树的用途大致为以下几种

        1>某个子区间进行区间更新

        2>查询某个子区间的总和

        3>查询某个子区间的最值

    二.线段树的建立

      (1)节点的内容(一个节点代表一个区间)

          1>NodeLeft-----该区间的左边界

          2>NodeRight-----该区间的右边界

          3>NodeMin--------该区间的最小值

          4>NodeMax------该区间的最大值

          5>NodeSum------该区间的总和

      (2)利用节点之间的下标表示它们所代表的区间之间的关系

             1>设父节点的编号为n,则其左半区间的编号为2*n,右半区间的编号为2*n+1

          2>设某个非总区间的编号为n,则其父区间编号为n/2

         

    三.线段树的实例使用及代码

      (1)实例背景

                 

        (2)建树

          1>将7个红包建立为一颗线段树

        

          2>建树代码

    struct Tree {//定义结构
            ll l,r;//节点左右端点
            ll sum;//求和 
            ll lazy;//延迟标记
            ll maxn;//最大值 
            ll minn;// 最小值 
    } t[MAXN<<2];//开4倍空间
    
    
    void push_up(ll rt) { //向上更新
        t[rt].sum = t[rt << 1].sum + t[rt << 1 | 1].sum;//更新和
        t[rt].maxn = max(t[rt << 1].maxn ,t[rt << 1 | 1].maxn);//更新最大值
        t[rt].minn = min(t[rt << 1].minn ,t[rt << 1 | 1].minn);//更新最小值
    }
    
    
    void build(ll l,ll r, ll rt) { //建树,rt==root 
        t[rt].lazy = 0;
        t[rt].l=l;
        t[rt].r=r;
        if(l == r) {
            scanf("%lld",&t[rt].sum);//单个红包时输入金额
            t[rt].minn=t[rt].sum;
            t[rt].maxn=t[rt].sum;
            return;
        }
        ll mid = (l + r) >> 1;
        build(l,mid,rt<<1);
        build(mid+1,r,rt<<1|1);
        push_up(rt);//向上更新
    
    }

      (3)得到n~m的红包的金钱总额

     1 #define ll long long
     2 #define lson  rt << 1
     3 #define rson  rt << 1 | 1
     4 
     5 void push_down(ll rt, ll m) {//pushdown函数
     6     if(t[rt].lazy) { //若有标记,则将标记向下移动一层
     7         t[rt << 1].lazy += t[rt].lazy;
     8         t[rt << 1 | 1].lazy += t[rt].lazy;
     9         t[rt << 1].sum += (m - (m >> 1)) * t[rt].lazy;
    10         t[rt << 1 | 1].sum += (m >> 1) * t[rt].lazy;
    11         t[rt << 1].minn += t[rt].lazy;
    12         t[rt << 1 | 1].minn+= t[rt].lazy;
    13         t[rt << 1].maxn += t[rt].lazy;
    14         t[rt << 1 | 1].maxn+= t[rt].lazy;
    15         t[rt].lazy = 0;//取消本层标记
    16     }
    17 }
    18 
    19 ll query(ll L, ll R, ll rt) { //区间求和
    20     if(L <= t[rt].l && R >= t[rt].r) {//如果当前节点所代表的区间包含于所求区间
    21         return t[rt].sum;//直接返回sum
    22     }
    23     push_down(rt, t[rt].r - t[rt].l + 1);//向下更新,对lazy标记进行处理
    24     ll mid = (t[rt].r + t[rt].l) >> 1;
    25     ll ans = 0;
    26     if(L <= mid) ans += query(L, R, lson);//分两边递归
    27     if(R > mid) ans += query(L, R, rson);
    28     return ans;
    29 }

      (4)更新n~m的金钱数

    void update(ll L,ll R, ll key, ll rt) { //区间更新
        if(L <= t[rt].l && R >= t[rt].r) {
            t[rt].sum+=(t[rt].r - t[rt].l + 1) * key;
            t[rt].minn+=key;
            t[rt].maxn+=key;
            t[rt].lazy+=key;
            return;
        }
        push_down(rt, t[rt].r - t[rt].l + 1);//向下更新
        ll mid = (t[rt].r + t[rt].l) >> 1;
        if(L <= mid) update(L, R, key, lson);
        if(R > mid) update(L, R, key, rson);
        push_up(rt);//向上更新
    }

      (5)寻找最值

    ll query_min(ll L, ll R, ll rt) { //区间求最小值
        if(L <= t[rt].l && R >= t[rt].r) {
            return t[rt].minn;
        }
        push_down(rt, t[rt].r - t[rt].l + 1);//向下更新
        ll mid = (t[rt].r + t[rt].l) >> 1;
        ll ans = 0x3f3f3f3f;
        if(L <= mid) ans = min(ans,query_min(L, R, lson));
        if(R > mid) ans =min(ans,query_min(L, R, rson)) ;
        return ans;
    }
    
    ll query_max(ll L, ll R, ll rt) { //区间求最大值
        if(L <= t[rt].l && R >= t[rt].r) {
            return t[rt].maxn;
        }
        push_down(rt, t[rt].r - t[rt].l + 1);//向下更新
        ll mid = (t[rt].r + t[rt].l) >> 1;
        ll ans = 0;
        if(L <= mid) ans = max(ans,query_max(L, R, lson));
        if(R > mid) ans = max(ans,query_max(L, R, rson));
        return ans;
    }
  • 相关阅读:
    Array中数据强制数据类型转换
    去除socket编程当中接收到的多余符\0
    <转>在 ASP.NET 中执行 URL 重写
    小牛生产小牛的问题解决集粹
    SAP ABAP鸟瞰【AV+PPT】
    cx_Oracle说:Python访问Oracle并不难
    resolve.conf引起登录HPUX的CDE故障
    HPUX 11i v2安装使用python 2.5.2
    HPUX下使用python发送邮件
    HPUX 11i v2上Oracle10.2基本安装指南
  • 原文地址:https://www.cnblogs.com/PokimonMaster/p/12208825.html
Copyright © 2020-2023  润新知