算法 {懒标记线段树}

算法 {懒标记线段树}

懒标记线段树

模板

//{ ___SegmentTree_Lazy_
struct ___SegmentTree_Lazy_{
using UnderlyingArray_ = ?; // 线段树维护的底层数组是`underlyingARRAY[0,1,...,__Range)`;
friend ostream& operator<<( ostream & _cout, ___SegmentTree_Lazy_ const& _a){
    _cout<< "___SegmentTree_Lazy_-Debug-Begin\n";
    auto dfs = [&]( auto _dfs, Node_ * _cur)->void{
        if( _cur->Info.Interval.first != _cur->Info.Interval.second){
            _cur->SpreadLazy();
            _dfs( _dfs, _cur->SonPtr[0]);  _dfs( _dfs, _cur->SonPtr[1]);
            _cur->Info.Merge( _cur->SonPtr[0]->Info, _cur->SonPtr[1]->Info);
        }
        _cout<< _cur->Info<< "\n";
    };
    if( _a.__RootNode != nullptr){ dfs( dfs, _a.__RootNode);}
    _cout<< "___SegmentTree_Lazy_-Debug-End\n";
    return _cout;
}
    struct Node_{
        struct Lazy_{
            int Add = 0;  ?
            void Clear(){
                Add = 0;
            }
            bool IsEmpty() const{
                if( Add != 0){ return false;}
                return true;
            }
            void Modify_ByLazy( Lazy_ const& _lazy){
                Add += _lazy.Add;
            }
        };
        struct Info_{ // 对于*非叶子节点* 其所有信息 必须可以由*其两个儿子*的信息 来推导出;
        friend ostream& operator<<( ostream & _cout, Info_ const& _a){
            return _cout<< TOstringITEMS_( _a.Interval, _a.Mi);
        }

            std::pair<int,int> Interval;
            long long Mi;  ?

            void Merge( Info_ const& _lef, Info_ const& _rig){ // `lef=[0-1];  rig=[2-3]`  则当前区间是`[0-3]`, 你需要根据`lef,rig`的信息 来推导出`[0-3]`区间的信息;
                Interval = {_lef.Interval.first, _rig.Interval.second};
                Mi = std::min( _lef.Mi, _rig.Mi);
            }
            void Modify_ByLazy( Lazy_ const& _lazy){
                Mi += _lazy.Add;
            }
        };

        Node_ * SonPtr[2];
        Info_ Info;
        Lazy_ Lazy;
        void Modify_ByLazy( Lazy_ const& _lazy){
            Info.Modify_ByLazy( _lazy);
            Lazy.Modify_ByLazy( _lazy);
        }
        void SpreadLazy(){
            if( Lazy.IsEmpty()){ return;}
            SonPtr[0]->Modify_ByLazy( Lazy);
            SonPtr[1]->Modify_ByLazy( Lazy);
            Lazy.Clear();
        }
    };

    std::vector< Node_> __Nodes;
    int __Range; // 线段树区间`[0...__Range)`;
    Node_ * __RootNode;

    void Initialize( UnderlyingArray_ const* _arr, int _length){
        ASSERTsystem_( _length > 0);
        __Range = _length;
        __Nodes.resize( __Range*2); // The maximum of nodesCount is `Range*2`;
        int usedNodes = 0;
        auto dfs = [&]( auto _dfs, int _l, int _r)->Node_*{
            auto cur = &__Nodes[ usedNodes ++];
            if( _l == _r){ // `cur`是叶子节点
                cur->Lazy.Clear();
                auto & info = cur->Info;  info.Interval = {_l,_l};
                //>> 使用`_arr[_l]`来更新`info`;
                info.Mi = _arr[_l];
            }
            else{
                int mid = (_l+_r)>>1;  cur->SonPtr[0] = _dfs( _dfs, _l, mid);  cur->SonPtr[1] = _dfs( _dfs, mid+1, _r);
                cur->Info.Merge( cur->SonPtr[0]->Info, cur->SonPtr[1]->Info);
            }
            return cur;
        };
        __RootNode = dfs( dfs, 0, __Range-1);
    }
    void Modify_Interval( int const _l, int const _r, Node_::Lazy_ const& _lazy){ // 對`[_l,_r]`區間裏的每個元素 都執行`_lazy`操作;
        ASSERTsystem_( 0<=_l && _l<=_r && _r<__Range);
        auto Dfs = [&]( auto _dfs, Node_ * _cur)->void{
            if( _l<=_cur->Info.Interval.first && _r>=_cur->Info.Interval.second){
                _cur->Modify_ByLazy( _lazy);
                return;
            }
            _cur->SpreadLazy();
            int mid = (_cur->Info.Interval.first + _cur->Info.Interval.second)>>1;
            if( _l <= mid){ _dfs( _dfs, _cur->SonPtr[0]);}  if( _r > mid){ _dfs( _dfs, _cur->SonPtr[1]);}
            _cur->Info.Merge( _cur->SonPtr[0]->Info, _cur->SonPtr[1]->Info);
        };
        Dfs( Dfs, __RootNode);
    }
    Node_::Info_ Query_Interval( int const _l, int const _r){
        ASSERTsystem_( 0<=_l && _l<=_r && _r<__Range);
        auto Dfs = [&]( auto _dfs, Node_ * _cur)->Node_::Info_{
            if( _l<=_cur->Info.Interval.first && _r>=_cur->Info.Interval.second){ return _cur->Info;}
            _cur->SpreadLazy();
            int mid = (_cur->Info.Interval.first + _cur->Info.Interval.second)/2;
            if( _r <= mid){ return _dfs( _dfs, _cur->SonPtr[0]);} else if( _l > mid){ return _dfs( _dfs, _cur->SonPtr[1]);}
            Node_::Info_ ANS;  ANS.Merge( _dfs( _dfs, _cur->SonPtr[0]), _dfs( _dfs, _cur->SonPtr[1]));
            return ANS;
        };
        return Dfs( Dfs, __RootNode);
    }
};
//} ___SegmentTree_Lazy_

应用

@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=139552190;
两个数组A,B,求A[l]*B[l] +...+ A[r]*B[r]的值, 支持A[l...r] += add, B[l...r] += add;

@DELI;

@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=139426505;
环形数组;

筆記

class ___SegmentTree_Lazy{
public:
using __ArrayType_ = int; // 線段樹所維護的底層數組類型
    class __Lazy_{
    public:
        int Add = 0;

        void Clear(){
            Add = 0;
        }
        bool IsEmpty() const{
            if( Add != 0){ return 0;}
            return 1;
        }
    };
    class __Data_{
    public:
        pair<int,int> Interval;
        int64_t Sum;

        void Update_byMerging( const __Data_ & _lef, const __Data_ & _rig){ // 通過兩個兒子(`[a,b]和[b+1,c]`)的數據域 來更新*`[a,c]`的數據域*;
            ASSERT_SYSTEM_( _lef.Interval.second+1 == _rig.Interval.first);

            Interval = {_lef.Interval.first, _rig.Interval.second};

            Sum = _lef.Sum + _rig.Sum;
        }
        friend ostream& operator<<( ostream & _cout, const __Data_ & _a){
            return _cout<< "["<<_a.Interval.first<<"-"<<_a.Interval.second<<"]: {"<< "}";
        }
    }; // class __Data_
    class __Node_{
    public:
        __Node_ * SonPtr[2] = {nullptr, nullptr};
        __Data_ Data;
        __Lazy_ Lazy;

        void Initialize_leaf( const __ArrayType_ & _val){ // 執行底層數組`Arr[i]==val` 更新葉子節點`[i,i]`對應的*數據域*;
            ASSERT_SYSTEM_( Data.Interval.first == Data.Interval.second);

            //>> 數據域
                Data.Sum = _val;
            Lazy.Clear();
        }
        void Update_byLazy( const __Lazy_ & _lazy){
            if( _lazy.IsEmpty()){ return;}

            int curLength = Data.Interval.second - Data.Interval.first + 1;
            if( _lazy.Add != 0){ // 與`IsEmpty()`裏的判斷 要保持一致
                { // 更新*嬾標記*
                    Lazy.Add += _lazy.Add;
                }
                { // 更新*數據記*
                    Data.Sum += (_lazy.Add * curLength);
                }
            }
        }
        void Update_sonLazy(){
            SonPtr[0]->Update_byLazy( Lazy);  SonPtr[1]->Update_byLazy( Lazy);
            Lazy.Clear();
        }
    }; // class __Node_

    int __Range = 0; // 底層數組為`[0...Range)`;
    vector<__Node_> __Nodes;
    __Node_ * __Root;

    void Initialize( const __ArrayType_ * _arr, int _length){
        __Range = _length;  __Nodes.resize( __Range*2);  int __nodesCount=0;
        auto dfs = [&]( auto _dfs, int _ind, int _l, int _r){
            __Node_ * cur = &__Nodes[ __nodesCount ++];
            if( _l == _r){ cur->Data.Interval = {_l,_l};  cur->Initialize_leaf( _arr[_l]);}
            else{ int mid = (_l+_r)>>1;  cur->SonPtr[0] = _dfs( _dfs, _ind*2, _l, mid);  cur->SonPtr[1] = _dfs( _dfs, _ind*2+1, mid+1, _r);  cur->Data.Update_byMerging( cur->SonPtr[0]->Data, cur->SonPtr[1]->Data);}
            return cur;
        };
        __Root = dfs( dfs, 1, 0, __Range-1);
    }
    void Modify_interval( int _l, int _r, const __Lazy_ & _lazy){ // 對`[_l,_r]`區間裏的每個元素 都執行`_lazy`操作;
        ASSERT_SYSTEM_( 0<=_l && _l<=_r && _r<__Range);
        auto dfs = [&]( auto _dfs, __Node_ * _cur){
            if( _l<=_cur->Data.Interval.first && _r>=_cur->Data.Interval.second){ _cur->Update_byLazy( _lazy); return;}

            _cur->Update_sonLazy();
            int mid = (_cur->Data.Interval.first + _cur->Data.Interval.second)/2;
            if( _l <= mid){ _dfs( _dfs, _cur->SonPtr[0]);}  if( _r > mid){ _dfs( _dfs, _cur->SonPtr[1]);}
            _cur->Data.Update_byMerging( _cur->SonPtr[0]->Data, _cur->SonPtr[1]->Data);
        };
        dfs( dfs, __Root);
    }
    __Data_ Query_interval( int _l, int _r){
        ASSERT_SYSTEM_( 0<=_l && _l<=_r && _r<__Range);
        auto dfs = [&]( auto _dfs, __Node_ * _cur){
            if( _l<=_cur->Data.Interval.first && _r>=_cur->Data.Interval.second){ return _cur->Data;}

            _cur->Update_sonLazy();
            int mid = (_cur->Data.Interval.first + _cur->Data.Interval.second)/2;
            if( _r <= mid){ return _dfs( _dfs, _cur->SonPtr[0]);} else if( _l > mid){ return _dfs( _dfs, _cur->SonPtr[1]);}
            __Data_ ANS;  ANS.Update_byMerging( _dfs( _dfs, _cur->SonPtr[0]), _dfs( _dfs, _cur->SonPtr[1]));
            return ANS;
        };
        return dfs( dfs, __Root);
    }
    void Debug(){
        cout<< "___SegmentTree::Debug::Begin\n";
        function<void(__Node_*)> dfs = [&]( __Node_ * _cur){
            if( _cur->Data.Interval.first != _cur->Data.Interval.second){ _cur->Update_sonLazy(); dfs( _cur->SonPtr[0]);  dfs( _cur->SonPtr[1]);}
            cout<< _cur->Data<< "\n";
        };
        if( __Root != nullptr){ dfs( __Root);}
        cout<< "___SegmentTree::Debug::End\n";
    }
}; // class ___SegmentTree_Lazy

@DELI;

區間查詢的返回值, 不一定就是Data, 也就是 合併兩個子節點 不一定就是調用Update_bySon(她的效率可能很差); (這種情況 只在樹套樹裏存在);
單點修改時 也不一定是調用Update_bySon來維護數據域(她的效率 可能很差), 你可能通過 維護底層數組(前提是沒有區間修改操作) 然後對於當前區間 比如她的底層數組是[a,b,c,d] 然後修改後變成[a,b,C,d], 即你得到c 然後把他修改成C 觀察他對Data的影響, 而不是藉助兩個兒子的Data 來直接合併;
例題: @LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=135004103;

@DELI;

#Multi Delays#
When there are multiple Delays on a node, when it update_son, the order of the Delays when taking these Delays to update its sons is vital.
More Details

@DELI;

#The update_son operation in M o d i f y Modify Modify#

void modify_1( int _node_id, int _left, int _right){
    if( ( _left >= modify_1_left) && ( _right <= modify_1_right)){ //< Target-Interval contains the current whole segment.
        @Pos_0
        return;
    }
    update_son( _node_id, _left, _right);
    ...
}   

These two section can be swapped, it is still correct.

  • If update_son is first, then it means that when we at @Pos_0, the Delay of current-node is empty, so, the new Delay value can be relatively easy to calculate.
    But, it costs more times, because if we at @Pos_0, we can also do correct process without the operation of update_son.
  • If update-son is not the first (as above), it means when we at @Pos_0, the Delay of current-node maybe not empty.

Whichever the case, the v a l u e value value of current-node are same, the only difference is whether Delay of current-node is empty.


@DELI;

#A special case#
We have a array A A A [ 1 , 2 , 3 , . . . ] [1, 2, 3, ...] [1,2,3,...], they are all zeros initially, there are two operations:

  • interval-modify, [ l , r ] + = k [l, r] += k [l,r]+=k, (k may be negative)
  • whole-array-query, ∑ i = 1 n ( A [ i ] > 0 ? 1 : 0 ) \displaystyle \sum_{i = 1}^{n} (A[i] > 0 ? 1 : 0) i=1n(A[i]>0?1:0)

Because the interval-modify, so the Delay for k k k is needed, the information of a node:

  • answer (corresponding to the query above), it equals to l s o n . a n s w e r + r s o n . a n s w e r lson.answer + rson.answer lson.answer+rson.answer.
  • value (for a leaf node, it denotes k k k according to mentioned above), but what’s the meaning for a non-leaf node?
  • Delay-value

Discuss the v a l u e value value of a non-leaf node (suppose a operation m o d i f y ( l , r , k ) modify( l,r, k) modify(l,r,k) and a non-leaf node c c c is contained by [ l , r ] [l, r] [l,r]:

  • if it is defined to l s o n . v a l u e + r s o n . v a l u e lson.value + rson.value lson.value+rson.value, when DFS-Modify at c c c, the v a l u e value value of c c c can be updated correctly, but the a n s w e r answer answer of c c c can’t be updated by k k k correctly.
  • If it is defined to m i n ( l s o n . v a l u e , r s o n . v a l u e ) min( lson.value, rson.value) min(lson.value,rson.value), when DFS-Modify at c c c, the v a l u e value value of c c c can be updated correctly, for a n s w e r answer answer of c c c. it still can’t be derived by k k k correctly.
    … if the updated v a l u e value value of c c c is > 0 > 0 >0, then a n s w e r answer answer equals to the length of the segment of c c c.
    … but, if the updated v a l u e value value of c c c if ≤ 0 \le 0 0, the correct a n s w e r answer answer is not solvable by the original a n s w e r answer answer and k k k.

In summary, there is no clear relation (formula) between a n s w e r answer answer and k k k of a non-leaf node ( k k k is the interval-modify acted on this node)

@DELI;

#Interval-modify#

When Modify, for a non-leaf node c c c which is contained by the target-modify-interval, then DFS will return at this node without visiting its sons.
Then, the information of c c c will be updated by m o d i f y v a l modify_{val} modifyval and the Delay of c c c will be added by m o d i f y v a l modify_{val} modifyval.

Because, here the information of c c c is updated by m o d i f y v a l modify_{val} modifyval, not by its two sons, so you must ensure this process is feasible.
(Traditionally, the information of any non-leaf node only depends on its two sons, but here it is not)
More details

@DELI;

#Delay-Version#
Traditional, we know that the information of a node equals to (or depends on) the information of its L s o n Lson Lson and R s o n Rson Rson.
But, in the Delay-Version, it is not always the case.

When Modify, for a node c c c which is contained by the target-modify-interval, then DFS will return at this node without visiting its sons.
So, the information of c c c will be updated by m o d i f y v a l modify_{val} modifyval (make sure the information of c c c is absolutely correct), and the delay-flag of c c c will by added by m o d i f y v a l modify_{val} modifyval.
As a result, the information of any node that is a (grand)son of c c c is wrong (due to there has a delay-flag of c c c), on the other hand, the information of c c c not equals to the information of its two sons.

The information of a node is correct, if and only if, any of its (grand)father node has no Delay.


Another property of Delay is, suppose there is a Delay at node c c c (that means the information of any node which is a (grand)son of c c c is wrong).
Now, we locate at c c c and are going to visit to l s o n lson lson (the left-son of c c c) (the DFS may be Modify, or Query, anyway), we need to perform the operation u p d a t e s o n update_son updateson to deliver the Delay of c c c to updating its two sons (make sure the information of its two sons is correct when we visit it)
So, we need use the Delay of c c c to update the information of l s o n lson lson. Therefore, you must ensure that the information of a l s o n lson lson (i.e., a interval) can be updated by a m o d i f y v a l modify_{val} modifyval (Delay means the m o d i f y v a l modify_{val} modifyval essentially), not by its two sons (because the information of its two sons is wrong)
More details

@DELI;

#The nature of M o d i f y & Q u e r y Modify\&Query Modify&Query#
For a target interval [ l , r ] [l, r] [l,r] (either Modify or Query), it will divided into several sub-intervals according to the structure of this Segment-Tree.
Assuming it divided into [ l , a ] [ a + 1 , b ] [ b + 1 , r ] [l, a] [a+1, b] [b+1, r] [l,a][a+1,b][b+1,r], each of these sub-intervals corresponds to a unique i d id id
Let’s call these 3 3 3 i d id ids be the set i d c u r id_{cur} idcur, and the set of the i d id id of all a n c e s t o r ancestor ancestors of i d c u r id_{cur} idcur be i d f a id_{fa} idfa

i d c u r id_{cur} idcur and i d f a id_{fa} idfa are the nodes that D F S DFS DFS visited.

@DELI;

#根节点必须是1#
线段树的各个节点, 就对应: (数组下标); 根节点, 不可以使用0下标!!!
这会导致, 他的左儿子的下标是0 * 2 = 0!!!

所以, 根必须是1

@DELI;

#区间范围#
线段树所维护的区间, 可以包含负数, 比如, 要维护的区间是: [L, R],
则: 线段树的总节点个数是 M = ( R − L + 1 ) ∗ 3 M = (R-L+1) * 3 M=(RL+1)3, 也就对应线段树数组的下标 Tree tr[ M];
即, 所有节点的下标是: [ 0 , M ] [0, M] [0,M]范围

但是, 这并不是说明, [L, R]的范围是[0, M]范围; 这是两个不同的概念

比如, [L, R]是: [-10, -2]

@DELI;

#下取整#
因为会涉及负数, 和二分一样, 要考虑(下取整)问题;

将[l, r], 令 m i d = ( l + r ) d i v i d e 2 mid = (l + r) divide 2 mid=(l+r)divide2, 分成了: [l, mid] 和 [mid+1, r]
… 那么, 如果[l,r]不是叶子节点, 就必须要保证: [l, mid]或[mid+1, r], 不会和[l, r]一样; 否则就死循环了;

比如: [-5, -6]; 如果用向0取整 m i d = − 11 / 2 = − 6 mid = -11 / 2 = -6 mid=11/2=6, 那么会变成[-5, -6] [-7, -6], 可以发现, 死循环了!

因此, 要用: m i d = ( l + r ) > > 1 mid = (l + r) >> 1 mid=(l+r)>>1 严格向下取整;

@DELI;

#线段树#
给定一个区间[L, R] (可以涉及负数), 要频繁的(查询/修改) 其中某个(连续的子区间)

线段树是对于一个区间, 分成了: 若干个子区间;
比如 [ 3 , 10 ] , 是分成为 : [ 3 , 3 ] [ 4 , 7 ] [ 7 , 10 ] 比如[3, 10], 是分成为: [3, 3] [4, 7] [7, 10] 比如[3,10],是分成为:[3,3][4,7][7,10]

即, 转换为了: (非重复覆盖问题); 而因为可重复覆盖问题, 一定可以转换为: 非重复覆盖问题; 因此, 这两类 都能用线段树;

@DELI;

#DFS sub-Tree#
Every interval [L, R] (whatever Query or Modify), corresponding to a DFS sub-Tree.

[--------] (1)
[----]      [----] (2,3)
[--]   [--]  [--]   -- (4,5,6,7)
- {[-]  - -   - -} - - (8,9,10,11,12,13,14,15)

the [] segments means the path of DFS, the {} means the target interval. (index starts with 1)

The interval {-----} [2,6], corresponds to the sub-Tree {1,2,3,4,5,6,9}.

For a given target interval [L, R] (whatever for Query or Modify), DFS would only visit those nodes which is intersect the target interval [L, R] (and its father node is not totally within [L, R], if so, then the DFS will return at the father node without visiting its son-nodes) – That is a pivotal property in Segment-Tree

The leaves of this sub-Tree {9, 5, 6}, exactly corresponding to the target interval [L=2, R=6] ([2, 2]–the segment of 9-node, [3, 4]–the segment of 5-node, [5, 6]–the segment of 6-node). So you need to merge the information of those leaves {9, 5, 6}. For instance, at the node-2, you should return the information which merges the information of node-9 and node-5 (note, the information returned by node-2 differs from the information of node-2 stored by the Segment-Tree. More precisely, the information of the former means the interval [2,3,4], the information of the latter means the interval [1,2,3,4])


We classify these visited nodes by DFS (i.e., the nodes of DFS sub-Tree), assuming c c c is one visited node, l , r l, r l,r be its sons, and the target interval is [L, R]. For a visited node c c c (the segment of c c c is intersected with [L, R]):

  • Being totally contained (such nodes like {9, 5, 6}), return the information of this node (the information is being sustained by the Segment-Tree), i.e. return node[ c] it contains all the information in this segment.

  • Only intersect right-son (such nodes like {4}), proceeding return what is returned by DFS, that is return DFS( r). (Note, DFS( r) is not necessary equal to node[ r], because r r r may be partially intersected or total contained (it is true for the latter), next section will be explained in detail)

  • Only intersect left-son (such nodes like {3}) return DFS( l);

  • Intersect both left-right son, but not being totally contained (such nodes like {1, 2})

    --------    (c)
    -[--- ----] (l,r)
    
    [] means the target interval [L,R]
    

    And we have auto ll = DFS( l), rr = DFS( r).
    There is a very crucial property, due to the target interval [L,R] is a interval, the intersection between [L,R] and l l l must be a suffix of l l l, the same as r r r must be a prefix of r r r. That means the union of the prefix and suffix is a consecutive interval in c c c.

    There will never has a case in which the intersection of [L,R] and l l l is not a suffix of l l l and the intersection of [L,R] and r r r is not a prefix of r r r.

    so, we let l l ll ll be the information of the intersection of [L,R] and l l l (just like the Segment-Tree, as we know, the information of l l l means the information of its segment, but now l l ll ll means the information of the suffix of its segment), r r rr rr be the information of the intersection of [L, R] and r r r. And then merge l l , r r ll, rr ll,rr just like the update_fa operation of Segment-Tree.

    So, the Query-function has a return N o d e Node Node, Node v = DFS( c) it means the information of the intersection of node- c c c and the target interval [L, R] is evaluated to v v v.

@DELI;

#区间判断#
线段树的核心, 就是(区间)的修改和查询 (如果是单点, 可以转换为长度为1的区间)

比如cur为当前遍历的线段树节点的区间, tar为要操作的区间; (且, 此时保证: tar和cur一定是相交的, 即有)
TODO

@DELI;

#节点个数#
假如区间范围是[L, R] (可以有负数), 即区间长是: M = R-L+1; 即叶子节点有M个

那么, 线段树的节点数, 可不是(M * 2); … 如果这么想, 是把线段树当成是: 完全二叉树了…

线段树虽然是二叉树, 但并不是完全二叉树;

区间长是M, 他最多分Log2(M) + 1次, 可以到达叶子节点; (比如对于[1, 100]区间, 要达到叶子节点, 要走7步; 而log2(100) = 6)
即数的高度是(Log2(M) + 2) … 要包括根节点;
那么, 一个高度为h的树, 最多有 2 h − 1 2^h-1 2h1个节点; 即 M ∗ 4 M*4 M4个节点

@DELI;

一个线段树的定义 是否合法, 即他的数据域是否是合格的, 怎么判断呢?
看2个函数, Modify_node( c, val) 和 updata_fa( fa, lson, rson); 比如说 你的Modify_node函数 用val去更新c的数据域, 如果你需要借助c儿子信息 那这是不行的, 即必须保证: 单纯使用val 就可以更新c的数据域;

@DELI;

Interval不符合數據域, 因為葉子節點無法維護; 她是線段樹的本質屬性, 不屬於用戶的數據;

@DELI;

class ___SegmentTree{
public:
using __ArrayType_ = ?; // 線段樹所維護的底層數組類型
class __Node_{ // 節點分為2類: {線段樹裡的固有節點, `Query_interval`所拼接的返回值節點};
public:
    class __Lazy_{
    public:
        ? int Add = 0;

        void Clear(){
            ? Add = 0;
        }
        bool IsEmpty() const{
            ? if( Add != 0){ return false;}
            return true;
        }
        friend ostream& operator<<( ostream& _cout, const __Lazy_ & _a){
            return _cout<< "@TODO";
        }
    };
    class __Data_{ // 数据域 (必須滿足: 對於非葉子節點的數據域 一定可以由其`SonPtr[0|1].數據域`所維護)
    public:
        ? int64_t Sum;

        void Initialize_leaf( const __ArrayType_ & _val){ // 葉子節點`[i,i]` 此時底層數組`Arr[i]==val` 更新其對應的*數據域*;
            ? Sum = _val;
        }
    };

    __Node_ * SonPtr[2] = {nullptr, nullptr};
    std::pair<int,int> Interval;

    __Lazy_ Lazy;
    __Data_ Data;

    void Update_bySon(){ // 利用`SonPtr[0|1].{數據域}` 來更新 當前點的*所有的數據域*;
        ASSERT_WEAK_( Interval.first != Interval.second); // 不是葉子節點
        { // Data.Sum
            Data.Sum = SonPtr[0]->Data.Sum + SonPtr[1]->Data.Sum;
        }
    }
    void __Modify_byLazy( const __Lazy_ & _lazy){
        int len = Interval.second-Interval.first+1;
        {
            if( _lazy.Add != 0){ // 這裡要與`__Lazy_::IsEmpty`的判斷 相對應
                const auto & lazy = _lazy.Add;
                //>> 用`lazy`來更新`Lazy`;
                Lazy.Add += lazy;
                //>> 用`lazy`來更新*所有涉及到的數據域*;
                Data.Sum += lazy * len;
            }
        }
    }
    void UpdateSon_byLazy(){
        if( Lazy.IsEmpty() || SonPtr[0]==nullptr){ return;}
        SonPtr[0]->__Modify_byLazy( Lazy);  SonPtr[1]->__Modify_byLazy( Lazy);  Lazy.Clear();
    }
    friend ostream& operator<<( ostream & _cout, const __Node_ & _a){
        return _cout<< "@TODO";
    }
};

int __Range = 0; // 底層數組為`[0...Range)`;
__Node_ * __Root = nullptr;

~___SegmentTree(){
    function<void(__Node_*)> dfs = [&]( __Node_ * _cur){ if( _cur->SonPtr[0] != nullptr){ dfs( _cur->SonPtr[0]);  dfs( _cur->SonPtr[1]);} delete _cur;};
    if( __Root != nullptr){ dfs( __Root); __Root = nullptr;}
}
void Initialize( const vector<__ArrayType_> & _arr){
    __Range = _arr.size();
    function<__Node_*(int,int)> dfs = [&]( int _l, int _r){
        __Node_ * cur = new __Node_;  cur->Interval = {_l,_r};
        if( _l == _r){ cur->Data.Initialize_leaf( _arr[_l]);}
        else{ int mid = (_l+_r)>>1;  cur->SonPtr[0] = dfs( _l, mid);  cur->SonPtr[1] = dfs( mid+1, _r);  cur->Update_bySon();}
        return cur;
    };
    __Root = dfs( 0, __Range-1);
}
void Modify_oneArrayElement( int _ind, const __ArrayType_ & _data){ // 修改*底層數組*
    ASSERT_WEAK_( 0<=_ind && _ind<__Range);
    function<void(__Node_*)> dfs = [&]( __Node_ * _cur){
        _cur->UpdateSon_byLazy();
        if( _cur->SonPtr[0] == nullptr){ _cur->Data.Initialize_leaf( _data);}
        else{
            if( _ind <= _cur->SonPtr[0]->Interval.second){ dfs( _cur->SonPtr[0]);} else{ dfs( _cur->SonPtr[1]);}
            //>> 更新`cur`的*數據域*; (不一定就是`_cur->Update_bySon()` 因為他可能效率很低);
            _cur->Update_bySon();
        }
    };
    dfs( __Root);
}
void Modify_intervalLazy( int _l, int _r, const __Node_::__Lazy_ & _lazy){ // 修改*底層數組*
    ASSERT_WEAK_( 0<=_l && _l<=_r && _r<__Range);
    function<void(__Node_*)> dfs = [&]( __Node_ * _cur){
        _cur->UpdateSon_byLazy();
        if( _l<=_cur->Interval.first && _r>=_cur->Interval.second){ _cur->__Modify_byLazy( _lazy); return;}
        int mid = (_cur->Interval.first+_cur->Interval.second)>>1;
        if( _l <= mid){ dfs( _cur->SonPtr[0]);}  if( _r > mid){ dfs( _cur->SonPtr[1]);}
        _cur->Update_bySon();
        return;
    };
    dfs( __Root);
}
using __RetType_Query_ = ?;
__RetType_Query_ Get_intervalData( int _l, int _r){
    ASSERT_WEAK_( 0<=_l && _l<=_r && _r<__Range);
    function<__RetType_Query_(__Node_*)> dfs = [&]( __Node_ * _cur){
        _cur->UpdateSon_byLazy();
        if( _l<=_cur->Interval.first && _r>=_cur->Interval.second){ // `cur`不一定是*葉子節點*;
            ? return _cur->Data.Sum;
        }
        int mid = (_cur->Interval.first+_cur->Interval.second)>>1;
        if( _r <= mid){ return dfs( _cur->SonPtr[0]);} else if( _l > mid){ return dfs( _cur->SonPtr[1]);}
        auto lef = dfs( _cur->SonPtr[0]), rig = dfs( _cur->SonPtr[1]);
        ? return __RetType_Query_(1);
    };
    return dfs( __Root);
}
void Debug(){
    cout<< "___SegmentTree::Debug::Begin\n";
    function<void(__Node_*)> dfs = [&]( __Node_ * _cur){
        _cur->UpdateSon_byLazy();
        if( _cur->SonPtr[0] == nullptr){
            cout<< _cur->Interval.first<< ": "<< *_cur<< "\n";
            return;
        }
        else{ dfs( _cur->SonPtr[0]);  dfs( _cur->SonPtr[1]);}
        _cur->Update_bySon();
    };
    if( __Root != nullptr){ dfs( __Root);}
    cout<< "___SegmentTree::Debug::End\n";
}
}; // class ___SegmentTree
  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值