算法 {懒标记线段树}
懒标记线段树
模板
//{ ___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 ofupdate_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=1∑n(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=(R−L+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 tonode[ 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
2h−1个节点; 即
M
∗
4
M*4
M∗4个节点
@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