Skip to content

Commit a9fa8db

Browse files
authored
Update README.markdown
After code review to update readme.md
1 parent 433d1f9 commit a9fa8db

File tree

1 file changed

+70
-31
lines changed

1 file changed

+70
-31
lines changed

Segment Tree/LazyPropagation/README.markdown

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public func query(leftBound: Int, rightBound: Int) -> T {
7171
Position ① means that the left bound of current query interval is on the right of this right bound, so recurs to right direction. Position ② is opposite of position ①, recurs to left direction. Position ③ means our check interval is included the interval we need, so recurs deeply.
7272

7373
![pushUp](Images/pushUp.png)
74+
7475
There are common part from the two parts of code above - **recurs deeply below, and update data up**. So we can decouple this operation named `func pushUp(lson: LazySegmentTree, rson: LazySegmentTree)`:
7576

7677
```swift
@@ -90,26 +91,32 @@ public init(array: [Int], leftBound: Int, rightBound: Int) {
9091
self.rightBound = rightBound
9192
self.value = 0
9293
self.lazyValue = 0
93-
if leftBound == rightBound {
94+
95+
guard leftBound != rightBound else {
9496
value = array[leftBound]
9597
return
9698
}
97-
let middle = (leftBound + rightBound) / 2
99+
100+
let middle = leftBound + (rightBound - leftBound) / 2
98101
leftChild = LazySegmentTree(array: array, leftBound: leftBound, rightBound: middle)
99102
rightChild = LazySegmentTree(array: array, leftBound: middle + 1, rightBound: rightBound)
100-
pushUp(lson: leftChild!, rson: rightChild!)
103+
if let leftChild = leftChild, let rightChild = rightChild {
104+
pushUp(lson: leftChild, rson: rightChild)
105+
}
101106
}
102107
// MARK: - One Item Update
103-
public func update(index: Int, newValue: Int) {
104-
if self.leftBound == self.rightBound {
105-
self.value = newValue
108+
public func update(index: Int, incremental: Int) {
109+
guard self.leftBound != self.rightBound else {
110+
self.value += incremental
106111
return
107112
}
108113
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
109114
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
110-
let middle = (self.leftBound + self.rightBound) / 2
111-
if index <= middle { leftChild.update(index: index, newValue: newValue) }
112-
else { rightChild.update(index: index, newValue: newValue) }
115+
116+
let middle = self.rightBound + (self.leftBound - self.rightBound) / 2
117+
118+
if index <= middle { leftChild.update(index: index, incremental: incremental) }
119+
else { rightChild.update(index: index, incremental: incremental) }
113120
pushUp(lson: leftChild, rson: rightChild)
114121
}
115122
```
@@ -132,11 +139,13 @@ It is a `O(n)` time operation, which make the interval operation uses `O(nlogn)`
132139
Check the data structure of Segment Tree again:
133140

134141
![Segment-tree](Images/Segment-tree.png)
142+
135143
We only catch the root node in programming. If we want to explore the bottom of the tree, and use `pushUp` to update every node, the task will be reached. So it asked us to traverse the tree, that spent `O(n)` time to do this with any way. This can't conform our expectations.
136144

137145
Then we started to think about `pushDown` to update down from the root. **After we update the parent, the data continued to distributed to its children according to law.** But it still need `O(n)` time to do this. Keep thinking, we **only update the parent, and to update the children when `query` time**. Yeah, that's the key of **lazy propagation**. Because the recursing direct of the `query` and `update interval` is same. So we got it! 😁 Let's check this sample:
138146

139147
![lazy-sample-2](Images/lazy-sample-2.png)
148+
140149
`update` make the subscript 1...3 elements plus 2, so we make the 1st node in 2 depth and 3rd in 3 depth get a *lazy mark*, which means these node need to be updated. And we shouldn't add a *lazy mark* for root node, because it was updated before the `pushDown` in the first recursing.
141150

142151
In `query` operation, we accord to the original method to recurs the tree, and find the 1st node held *lazy mark* in 2 depth, so to update it. It's the same situation about the 1st node in 3 depth.
@@ -147,85 +156,115 @@ This is the complete implementation about the Sum Segment Tree with interval upd
147156

148157
```swift
149158
public class LazySegmentTree {
159+
150160
private var value: Int
161+
151162
private var leftBound: Int
163+
152164
private var rightBound: Int
165+
153166
private var leftChild: LazySegmentTree?
167+
154168
private var rightChild: LazySegmentTree?
169+
155170
// Interval Update Lazy Element
156171
private var lazyValue: Int
172+
157173
// MARK: - Push Up Operation
174+
// Description: pushUp() - update items to the top
158175
private func pushUp(lson: LazySegmentTree, rson: LazySegmentTree) {
159176
self.value = lson.value + rson.value
160177
}
178+
161179
// MARK: - Push Down Operation
180+
// Description: pushDown() - update items to the bottom
162181
private func pushDown(round: Int, lson: LazySegmentTree, rson: LazySegmentTree) {
163-
if lazyValue != 0 {
164-
lson.lazyValue += lazyValue
165-
rson.lazyValue += lazyValue
166-
lson.value += lazyValue * (round - (round >> 1))
167-
rson.value += lazyValue * (round >> 1)
168-
lazyValue = 0
169-
}
182+
guard lazyValue != 0 else { return }
183+
lson.lazyValue += lazyValue
184+
rson.lazyValue += lazyValue
185+
lson.value += lazyValue * (round - (round >> 1))
186+
rson.value += lazyValue * (round >> 1)
187+
lazyValue = 0
170188
}
189+
171190
public init(array: [Int], leftBound: Int, rightBound: Int) {
172191
self.leftBound = leftBound
173192
self.rightBound = rightBound
174193
self.value = 0
175194
self.lazyValue = 0
176-
if leftBound == rightBound {
195+
196+
guard leftBound != rightBound else {
177197
value = array[leftBound]
178198
return
179199
}
180-
let middle = (leftBound + rightBound) / 2
200+
201+
let middle = leftBound + (rightBound - leftBound) / 2
181202
leftChild = LazySegmentTree(array: array, leftBound: leftBound, rightBound: middle)
182203
rightChild = LazySegmentTree(array: array, leftBound: middle + 1, rightBound: rightBound)
183-
pushUp(lson: leftChild!, rson: rightChild!)
204+
if let leftChild = leftChild, let rightChild = rightChild {
205+
pushUp(lson: leftChild, rson: rightChild)
206+
}
184207
}
208+
185209
public convenience init(array: [Int]) {
186210
self.init(array: array, leftBound: 0, rightBound: array.count - 1)
187211
}
212+
188213
public func query(leftBound: Int, rightBound: Int) -> Int {
189214
if leftBound <= self.leftBound && self.rightBound <= rightBound {
190215
return value
191216
}
192217
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
193218
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
219+
194220
pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild)
195-
let middle = (self.leftBound + self.rightBound) / 2
221+
222+
let middle = self.leftBound + (self.rightBound - self.leftBound) / 2
196223
var result: Int = 0
224+
197225
if leftBound <= middle { result += leftChild.query(leftBound: leftBound, rightBound: rightBound) }
198226
if rightBound > middle { result += rightChild.query(leftBound: leftBound, rightBound: rightBound) }
227+
199228
return result
200229
}
230+
201231
// MARK: - One Item Update
202232
public func update(index: Int, incremental: Int) {
203-
if self.leftBound == self.rightBound {
233+
guard self.leftBound != self.rightBound else {
204234
self.value += incremental
205235
return
206236
}
207237
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
208238
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
209-
let middle = (self.leftBound + self.rightBound) / 2
239+
240+
let middle = self.rightBound + (self.leftBound - self.rightBound) / 2
241+
210242
if index <= middle { leftChild.update(index: index, incremental: incremental) }
211243
else { rightChild.update(index: index, incremental: incremental) }
212244
pushUp(lson: leftChild, rson: rightChild)
213245
}
246+
214247
// MARK: - Interval Item Update
215248
public func update(leftBound: Int, rightBound: Int, incremental: Int) {
216249
if leftBound <= self.leftBound && self.rightBound <= rightBound {
217250
self.lazyValue += incremental
218251
self.value += incremental * (self.rightBound - self.leftBound + 1)
219252
return
220253
}
254+
221255
guard let leftChild = leftChild else { fatalError() }
222256
guard let rightChild = rightChild else { fatalError() }
257+
223258
pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild)
224-
let middle = (self.leftBound + self.rightBound) / 2
259+
260+
let middle = self.rightBound + (self.leftBound - self.rightBound) / 2
261+
225262
if leftBound <= middle { leftChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) }
226263
if middle < rightBound { rightChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) }
264+
227265
pushUp(lson: leftChild, rson: rightChild)
228266
}
267+
229268
}
230269
```
231270

@@ -238,15 +277,15 @@ private var lazyValue: Int
238277
Here we add a new property for Segment Tree to represent *lazy mark*. And it is a incremental value for Sum Segment Tree. If the `lazyValue` isn't equal to zero, the current node need to be updated. And its real value is equal to `value + lazyValue * (rightBound - leftBound + 1)`.
239278

240279
```swift
241-
// MARK: - Push Down Operation
280+
// MARK: - Push Down Operation
281+
// Description: pushDown() - update items to the bottom
242282
private func pushDown(round: Int, lson: LazySegmentTree, rson: LazySegmentTree) {
243-
if lazyValue != 0 {
244-
lson.lazyValue += lazyValue
245-
rson.lazyValue += lazyValue
246-
lson.value += lazyValue * (round - (round >> 1))
247-
rson.value += lazyValue * (round >> 1)
248-
lazyValue = 0
249-
}
283+
guard lazyValue != 0 else { return }
284+
lson.lazyValue += lazyValue
285+
rson.lazyValue += lazyValue
286+
lson.value += lazyValue * (round - (round >> 1))
287+
rson.value += lazyValue * (round >> 1)
288+
lazyValue = 0
250289
}
251290
```
252291

0 commit comments

Comments
 (0)