Skip to content

Commit 10d90da

Browse files
committed
Update the Segment Tree: add Lazy Propagation for interval update
Signed-off-by: Harry Twan <[email protected]>
1 parent fab5b98 commit 10d90da

File tree

8 files changed

+427
-0
lines changed

8 files changed

+427
-0
lines changed
33.5 KB
Loading
78.3 KB
Loading
29.8 KB
Loading
31.7 KB
Loading
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//: Playground - noun: a place where people can play
2+
3+
// last checked with Xcode 9.0b4
4+
#if swift(>=4.0)
5+
print("Hello, Swift 4!")
6+
#endif
7+
8+
//protocol SegmentTree<T> {
9+
// func pushUp(lson: T, rson: T)
10+
// func pushDown(round: Int, lson: T, rson: T)
11+
//}
12+
13+
public class LazySegmentTree {
14+
15+
private var value: Int
16+
17+
private var leftBound: Int
18+
19+
private var rightBound: Int
20+
21+
private var leftChild: LazySegmentTree?
22+
23+
private var rightChild: LazySegmentTree?
24+
25+
// Interval Update Lazy Element
26+
private var lazyValue: Int
27+
28+
// MARK: - Push Up Operation
29+
// Description: 这里是 push up 操作,用来对 Segment Tree 向上更新
30+
private func pushUp(lson: LazySegmentTree, rson: LazySegmentTree) {
31+
self.value = lson.value + rson.value
32+
}
33+
34+
// MARK: - Push Down Operation
35+
// Description: 这里是 push down 操作,用来对 Segment Tree 向下更新
36+
// Open Interface Function: 此处应该开放方法对齐进行 Override
37+
private func pushDown(round: Int, lson: LazySegmentTree, rson: LazySegmentTree) {
38+
if lazyValue != 0 {
39+
lson.lazyValue += lazyValue
40+
rson.lazyValue += lazyValue
41+
lson.value += lazyValue * (round - (round >> 1))
42+
rson.value += lazyValue * (round >> 1)
43+
lazyValue = 0
44+
}
45+
}
46+
47+
public init(array: [Int], leftBound: Int, rightBound: Int) {
48+
self.leftBound = leftBound
49+
self.rightBound = rightBound
50+
self.value = 0
51+
self.lazyValue = 0
52+
53+
if leftBound == rightBound {
54+
value = array[leftBound]
55+
return
56+
}
57+
58+
let middle = (leftBound + rightBound) / 2
59+
leftChild = LazySegmentTree(array: array, leftBound: leftBound, rightBound: middle)
60+
rightChild = LazySegmentTree(array: array, leftBound: middle + 1, rightBound: rightBound)
61+
pushUp(lson: leftChild!, rson: rightChild!)
62+
63+
}
64+
65+
public convenience init(array: [Int]) {
66+
self.init(array: array, leftBound: 0, rightBound: array.count - 1)
67+
}
68+
69+
public func query(leftBound: Int, rightBound: Int) -> Int {
70+
if leftBound <= self.leftBound && self.rightBound <= rightBound {
71+
return value
72+
}
73+
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
74+
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
75+
76+
pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild)
77+
78+
let middle = (self.leftBound + self.rightBound) / 2
79+
var result: Int = 0
80+
81+
if leftBound <= middle { result += leftChild.query(leftBound: leftBound, rightBound: rightBound) }
82+
if rightBound > middle { result += rightChild.query(leftBound: leftBound, rightBound: rightBound) }
83+
84+
return result
85+
}
86+
87+
// MARK: - One Item Update
88+
public func update(index: Int, incremental: Int) {
89+
if self.leftBound == self.rightBound {
90+
self.value += incremental
91+
return
92+
}
93+
guard let leftChild = leftChild else { fatalError("leftChild should not be nil") }
94+
guard let rightChild = rightChild else { fatalError("rightChild should not be nil") }
95+
96+
let middle = (self.leftBound + self.rightBound) / 2
97+
98+
if index <= middle { leftChild.update(index: index, incremental: incremental) }
99+
else { rightChild.update(index: index, incremental: incremental) }
100+
pushUp(lson: leftChild, rson: rightChild)
101+
}
102+
103+
// MARK: - Interval Item Update
104+
public func update(leftBound: Int, rightBound: Int, incremental: Int) {
105+
if leftBound <= self.leftBound && self.rightBound <= rightBound {
106+
self.lazyValue += incremental
107+
self.value += incremental * (self.rightBound - self.leftBound + 1)
108+
return
109+
}
110+
111+
guard let leftChild = leftChild else { fatalError() }
112+
guard let rightChild = rightChild else { fatalError() }
113+
114+
pushDown(round: self.rightBound - self.leftBound + 1, lson: leftChild, rson: rightChild)
115+
116+
let middle = (self.leftBound + self.rightBound) / 2
117+
118+
if leftBound <= middle { leftChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) }
119+
if middle < rightBound { rightChild.update(leftBound: leftBound, rightBound: rightBound, incremental: incremental) }
120+
121+
pushUp(lson: leftChild, rson: rightChild)
122+
}
123+
124+
}
125+
126+
let array = [1, 2, 3, 4, 1, 3, 2]
127+
128+
let sumSegmentTree = LazySegmentTree(array: array)
129+
130+
print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 10 = 1 + 2 + 3 + 4
131+
sumSegmentTree.update(index: 1, incremental: 2)
132+
print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 12 = 1 + 4 + 3 + 4
133+
sumSegmentTree.update(leftBound: 0, rightBound: 2, incremental: 2)
134+
print(sumSegmentTree.query(leftBound: 0, rightBound: 3)) // 18 = 3 + 6 + 5 + 4
135+
136+
for index in 2 ... 5 {
137+
sumSegmentTree.update(index: index, incremental: 3)
138+
}
139+
140+
141+
sumSegmentTree.update(leftBound: 0, rightBound: 5, incremental: 2)
142+
print(sumSegmentTree.query(leftBound: 0, rightBound: 2))
143+
144+
145+
146+
147+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='osx' last-migration='0800'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>

Segment Tree/LazyPropagation/LazyPropagation.playground/playground.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)