|
33 | 33 |
|
34 | 34 | <!-- 这里可写通用的实现逻辑 -->
|
35 | 35 |
|
| 36 | +树状数组。 |
| 37 | + |
| 38 | +树状数组,也称作“二叉索引树”(Binary Indexed Tree)或 Fenwick 树。 它可以高效地实现如下两个操作: |
| 39 | + |
| 40 | +1. **单点更新** `update(x, delta)`: 把序列 x 位置的数加上一个值 delta; |
| 41 | +1. **前缀和查询** `query(x)`:查询序列 `[1,...x]` 区间的区间和,即位置 x 的前缀和。 |
| 42 | + |
| 43 | +这两个操作的时间复杂度均为 `O(log n)`。 |
| 44 | + |
| 45 | +树状数组最基本的功能就是求比某点 x 小的点的个数(这里的比较是抽象的概念,可以是数的大小、坐标的大小、质量的大小等等)。 |
| 46 | + |
| 47 | +比如给定数组 `a[5] = {2, 5, 3, 4, 1}`,求 `b[i] = 位置 i 左边小于等于 a[i] 的数的个数`。对于此例,`b[5] = {0, 1, 1, 2, 0}`。 |
| 48 | + |
| 49 | +解决方案是直接遍历数组,每个位置先求出 `query(a[i])`,然后再修改树状数组 `update(a[i], 1)` 即可。当数的范围比较大时,需要进行离散化,即先进行去重并排序,然后对每个数字进行编号。 |
| 50 | + |
36 | 51 | <!-- tabs:start -->
|
37 | 52 |
|
38 | 53 | ### **Python3**
|
39 | 54 |
|
40 | 55 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
41 | 56 |
|
42 | 57 | ```python
|
| 58 | +class BinaryIndexedTree: |
| 59 | + def __init__(self, n): |
| 60 | + self.n = n |
| 61 | + self.c = [0] * (n + 1) |
| 62 | + |
| 63 | + @staticmethod |
| 64 | + def lowbit(x): |
| 65 | + return x & -x |
| 66 | + |
| 67 | + def update(self, x, delta): |
| 68 | + while x <= self.n: |
| 69 | + self.c[x] += delta |
| 70 | + x += BinaryIndexedTree.lowbit(x) |
| 71 | + |
| 72 | + def query(self, x): |
| 73 | + s = 0 |
| 74 | + while x > 0: |
| 75 | + s += self.c[x] |
| 76 | + x -= BinaryIndexedTree.lowbit(x) |
| 77 | + return s |
| 78 | + |
43 | 79 |
|
| 80 | +class StreamRank: |
| 81 | + |
| 82 | + def __init__(self): |
| 83 | + self.tree = BinaryIndexedTree(50010) |
| 84 | + |
| 85 | + def track(self, x: int) -> None: |
| 86 | + self.tree.update(x + 1, 1) |
| 87 | + |
| 88 | + def getRankOfNumber(self, x: int) -> int: |
| 89 | + return self.tree.query(x + 1) |
| 90 | + |
| 91 | + |
| 92 | +# Your StreamRank object will be instantiated and called as such: |
| 93 | +# obj = StreamRank() |
| 94 | +# obj.track(x) |
| 95 | +# param_2 = obj.getRankOfNumber(x) |
44 | 96 | ```
|
45 | 97 |
|
46 | 98 | ### **Java**
|
47 | 99 |
|
48 | 100 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
49 | 101 |
|
50 | 102 | ```java
|
| 103 | +class BinaryIndexedTree { |
| 104 | + private int n; |
| 105 | + private int[] c; |
| 106 | + |
| 107 | + public BinaryIndexedTree(int n) { |
| 108 | + this.n = n; |
| 109 | + c = new int[n + 1]; |
| 110 | + } |
| 111 | + |
| 112 | + public static int lowbit(int x) { |
| 113 | + return x & -x; |
| 114 | + } |
| 115 | + |
| 116 | + public void update(int x, int delta) { |
| 117 | + while (x <= n) { |
| 118 | + c[x] += delta; |
| 119 | + x += lowbit(x); |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + public int query(int x) { |
| 124 | + int s = 0; |
| 125 | + while (x > 0) { |
| 126 | + s += c[x]; |
| 127 | + x -= lowbit(x); |
| 128 | + } |
| 129 | + return s; |
| 130 | + } |
| 131 | +} |
| 132 | + |
| 133 | +class StreamRank { |
| 134 | + private BinaryIndexedTree tree; |
| 135 | + |
| 136 | + public StreamRank() { |
| 137 | + tree = new BinaryIndexedTree(50010); |
| 138 | + } |
| 139 | + |
| 140 | + public void track(int x) { |
| 141 | + tree.update(x + 1, 1); |
| 142 | + } |
| 143 | + |
| 144 | + public int getRankOfNumber(int x) { |
| 145 | + return tree.query(x + 1); |
| 146 | + } |
| 147 | +} |
| 148 | + |
| 149 | +/** |
| 150 | + * Your StreamRank object will be instantiated and called as such: |
| 151 | + * StreamRank obj = new StreamRank(); |
| 152 | + * obj.track(x); |
| 153 | + * int param_2 = obj.getRankOfNumber(x); |
| 154 | + */ |
| 155 | +``` |
| 156 | + |
| 157 | +### **C++** |
| 158 | + |
| 159 | +```cpp |
| 160 | +class BinaryIndexedTree { |
| 161 | +public: |
| 162 | + int n; |
| 163 | + vector<int> c; |
| 164 | + |
| 165 | + BinaryIndexedTree(int _n): n(_n), c(_n + 1){} |
| 166 | + |
| 167 | + void update(int x, int delta) { |
| 168 | + while (x <= n) |
| 169 | + { |
| 170 | + c[x] += delta; |
| 171 | + x += lowbit(x); |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + int query(int x) { |
| 176 | + int s = 0; |
| 177 | + while (x > 0) |
| 178 | + { |
| 179 | + s += c[x]; |
| 180 | + x -= lowbit(x); |
| 181 | + } |
| 182 | + return s; |
| 183 | + } |
| 184 | + |
| 185 | + int lowbit(int x) { |
| 186 | + return x & -x; |
| 187 | + } |
| 188 | +}; |
| 189 | + |
| 190 | +class StreamRank { |
| 191 | +public: |
| 192 | + BinaryIndexedTree* tree; |
| 193 | + |
| 194 | + StreamRank() { |
| 195 | + tree = new BinaryIndexedTree(50010); |
| 196 | + } |
| 197 | + |
| 198 | + void track(int x) { |
| 199 | + tree->update(x + 1, 1); |
| 200 | + } |
| 201 | + |
| 202 | + int getRankOfNumber(int x) { |
| 203 | + return tree->query(x + 1); |
| 204 | + } |
| 205 | +}; |
| 206 | + |
| 207 | +/** |
| 208 | + * Your StreamRank object will be instantiated and called as such: |
| 209 | + * StreamRank* obj = new StreamRank(); |
| 210 | + * obj->track(x); |
| 211 | + * int param_2 = obj->getRankOfNumber(x); |
| 212 | + */ |
| 213 | +``` |
| 214 | +
|
| 215 | +### **Go** |
| 216 | +
|
| 217 | +```go |
| 218 | +type BinaryIndexedTree struct { |
| 219 | + n int |
| 220 | + c []int |
| 221 | +} |
| 222 | +
|
| 223 | +func newBinaryIndexedTree(n int) *BinaryIndexedTree { |
| 224 | + c := make([]int, n+1) |
| 225 | + return &BinaryIndexedTree{n, c} |
| 226 | +} |
| 227 | +
|
| 228 | +func (this *BinaryIndexedTree) lowbit(x int) int { |
| 229 | + return x & -x |
| 230 | +} |
| 231 | +
|
| 232 | +func (this *BinaryIndexedTree) update(x, delta int) { |
| 233 | + for x <= this.n { |
| 234 | + this.c[x] += delta |
| 235 | + x += this.lowbit(x) |
| 236 | + } |
| 237 | +} |
| 238 | +
|
| 239 | +func (this *BinaryIndexedTree) query(x int) int { |
| 240 | + s := 0 |
| 241 | + for x > 0 { |
| 242 | + s += this.c[x] |
| 243 | + x -= this.lowbit(x) |
| 244 | + } |
| 245 | + return s |
| 246 | +} |
| 247 | +
|
| 248 | +type StreamRank struct { |
| 249 | + tree *BinaryIndexedTree |
| 250 | +} |
| 251 | +
|
| 252 | +func Constructor() StreamRank { |
| 253 | + tree := newBinaryIndexedTree(50010) |
| 254 | + return StreamRank{tree} |
| 255 | +} |
| 256 | +
|
| 257 | +func (this *StreamRank) Track(x int) { |
| 258 | + this.tree.update(x+1, 1) |
| 259 | +} |
| 260 | +
|
| 261 | +func (this *StreamRank) GetRankOfNumber(x int) int { |
| 262 | + return this.tree.query(x + 1) |
| 263 | +} |
51 | 264 |
|
| 265 | +/** |
| 266 | + * Your StreamRank object will be instantiated and called as such: |
| 267 | + * obj := Constructor(); |
| 268 | + * obj.Track(x); |
| 269 | + * param_2 := obj.GetRankOfNumber(x); |
| 270 | + */ |
52 | 271 | ```
|
53 | 272 |
|
54 | 273 | ### **...**
|
|
0 commit comments