zoukankan      html  css  js  c++  java
  • 线段树个人理解及模板

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

     (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;
    }
  • 相关阅读:
    android 多线程
    Uva 10881 Piotr’s Ants 蚂蚁
    LA 3708 Graveyard 墓地雕塑 NEERC 2006
    UVa 11300 Spreading the Wealth 分金币
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    HDU 4162 Shape Number
    HDU 1869 六度分离
    HDU 1041 Computer Transformation
    利用可变参数函数清空多个数组
  • 原文地址:https://www.cnblogs.com/PokimonMaster/p/12208825.html
Copyright © 2011-2022 走看看