|
60 | 60 |
|
61 | 61 | <!-- 这里可写通用的实现逻辑 -->
|
62 | 62 |
|
| 63 | +**方法一:树状数组** |
| 64 | + |
| 65 | +我们不妨记 $queries[i] = [l_i, r_i]$,其中 $l_i \le r_i$。如果 $l_i = r_i$ 或者 $heights[l_i] \lt heights[r_i]$,那么答案就是 $r_i$。否则,我们需要在所有满足 $j \gt r_i$,且 $heights[j] \gt heights[l_i]$ 的 $j$ 中找到最小的 $j$。 |
| 66 | + |
| 67 | +我们可以将 $queries$ 按照 $r_i$ 从大到小排序,用一个指针 $j$ 指向当前遍历到的 $heights$ 的下标。 |
| 68 | + |
| 69 | +接下来,我们遍历每个查询 $queries[i] = (l, r)$,对于当前查询,如果 $j \gt r$,那么我们循环将 $heights[j]$ 插入树状数组中。树状数组维护的是后缀高度(离散化后的高度)的下标的最小值。然后,我们判断是否满足 $l = r$ 或者 $heights[l] \lt heights[r]$,如果满足,那么当前查询的答案就是 $r$,否则,我们在树状数组中查询 $heights[l]$ 的下标的最小值,即为当前查询的答案。 |
| 70 | + |
| 71 | +时间复杂度 $O((n + m) \times \log n + m \times \log m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别为 $heights$ 和 $queries$ 的长度。 |
| 72 | + |
| 73 | +相似题目: |
| 74 | + |
| 75 | +- [2736. 最大和查询](/solution/2700-2799/2736.Maximum%20Sum%20Queries/README.md) |
| 76 | + |
63 | 77 | <!-- tabs:start -->
|
64 | 78 |
|
65 | 79 | ### **Python3**
|
66 | 80 |
|
67 | 81 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
68 | 82 |
|
69 | 83 | ```python
|
70 |
| - |
| 84 | +class BinaryIndexedTree: |
| 85 | + __slots__ = ["n", "c"] |
| 86 | + |
| 87 | + def __init__(self, n: int): |
| 88 | + self.n = n |
| 89 | + self.c = [inf] * (n + 1) |
| 90 | + |
| 91 | + def update(self, x: int, v: int): |
| 92 | + while x <= self.n: |
| 93 | + self.c[x] = min(self.c[x], v) |
| 94 | + x += x & -x |
| 95 | + |
| 96 | + def query(self, x: int) -> int: |
| 97 | + mi = inf |
| 98 | + while x: |
| 99 | + mi = min(mi, self.c[x]) |
| 100 | + x -= x & -x |
| 101 | + return -1 if mi == inf else mi |
| 102 | + |
| 103 | + |
| 104 | +class Solution: |
| 105 | + def leftmostBuildingQueries( |
| 106 | + self, heights: List[int], queries: List[List[int]] |
| 107 | + ) -> List[int]: |
| 108 | + n, m = len(heights), len(queries) |
| 109 | + for i in range(m): |
| 110 | + queries[i] = [min(queries[i]), max(queries[i])] |
| 111 | + j = n - 1 |
| 112 | + s = sorted(set(heights)) |
| 113 | + ans = [-1] * m |
| 114 | + tree = BinaryIndexedTree(n) |
| 115 | + for i in sorted(range(m), key=lambda i: -queries[i][1]): |
| 116 | + l, r = queries[i] |
| 117 | + while j > r: |
| 118 | + k = n - bisect_left(s, heights[j]) + 1 |
| 119 | + tree.update(k, j) |
| 120 | + j -= 1 |
| 121 | + if l == r or heights[l] < heights[r]: |
| 122 | + ans[i] = r |
| 123 | + else: |
| 124 | + k = n - bisect_left(s, heights[l]) |
| 125 | + ans[i] = tree.query(k) |
| 126 | + return ans |
71 | 127 | ```
|
72 | 128 |
|
73 | 129 | ### **Java**
|
74 | 130 |
|
75 | 131 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
76 | 132 |
|
77 | 133 | ```java
|
78 |
| - |
| 134 | +class BinaryIndexedTree { |
| 135 | + private final int inf = 1 << 30; |
| 136 | + private int n; |
| 137 | + private int[] c; |
| 138 | + |
| 139 | + public BinaryIndexedTree(int n) { |
| 140 | + this.n = n; |
| 141 | + c = new int[n + 1]; |
| 142 | + Arrays.fill(c, inf); |
| 143 | + } |
| 144 | + |
| 145 | + public void update(int x, int v) { |
| 146 | + while (x <= n) { |
| 147 | + c[x] = Math.min(c[x], v); |
| 148 | + x += x & -x; |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + public int query(int x) { |
| 153 | + int mi = inf; |
| 154 | + while (x > 0) { |
| 155 | + mi = Math.min(mi, c[x]); |
| 156 | + x -= x & -x; |
| 157 | + } |
| 158 | + return mi == inf ? -1 : mi; |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +class Solution { |
| 163 | + public int[] leftmostBuildingQueries(int[] heights, int[][] queries) { |
| 164 | + int n = heights.length; |
| 165 | + int m = queries.length; |
| 166 | + for (int i = 0; i < m; ++i) { |
| 167 | + if (queries[i][0] > queries[i][1]) { |
| 168 | + queries[i] = new int[] {queries[i][1], queries[i][0]}; |
| 169 | + } |
| 170 | + } |
| 171 | + Integer[] idx = new Integer[m]; |
| 172 | + for (int i = 0; i < m; ++i) { |
| 173 | + idx[i] = i; |
| 174 | + } |
| 175 | + Arrays.sort(idx, (i, j) -> queries[j][1] - queries[i][1]); |
| 176 | + int[] s = heights.clone(); |
| 177 | + Arrays.sort(s); |
| 178 | + int[] ans = new int[m]; |
| 179 | + int j = n - 1; |
| 180 | + BinaryIndexedTree tree = new BinaryIndexedTree(n); |
| 181 | + for (int i : idx) { |
| 182 | + int l = queries[i][0], r = queries[i][1]; |
| 183 | + while (j > r) { |
| 184 | + int k = n - Arrays.binarySearch(s, heights[j]) + 1; |
| 185 | + tree.update(k, j); |
| 186 | + --j; |
| 187 | + } |
| 188 | + if (l == r || heights[l] < heights[r]) { |
| 189 | + ans[i] = r; |
| 190 | + } else { |
| 191 | + int k = n - Arrays.binarySearch(s, heights[l]); |
| 192 | + ans[i] = tree.query(k); |
| 193 | + } |
| 194 | + } |
| 195 | + return ans; |
| 196 | + } |
| 197 | +} |
79 | 198 | ```
|
80 | 199 |
|
81 | 200 | ### **C++**
|
82 | 201 |
|
83 | 202 | ```cpp
|
84 |
| - |
| 203 | +class BinaryIndexedTree { |
| 204 | +private: |
| 205 | + int inf = 1 << 30; |
| 206 | + int n; |
| 207 | + vector<int> c; |
| 208 | + |
| 209 | +public: |
| 210 | + BinaryIndexedTree(int n) { |
| 211 | + this->n = n; |
| 212 | + c.resize(n + 1, inf); |
| 213 | + } |
| 214 | + |
| 215 | + void update(int x, int v) { |
| 216 | + while (x <= n) { |
| 217 | + c[x] = min(c[x], v); |
| 218 | + x += x & -x; |
| 219 | + } |
| 220 | + } |
| 221 | + |
| 222 | + int query(int x) { |
| 223 | + int mi = inf; |
| 224 | + while (x > 0) { |
| 225 | + mi = min(mi, c[x]); |
| 226 | + x -= x & -x; |
| 227 | + } |
| 228 | + return mi == inf ? -1 : mi; |
| 229 | + } |
| 230 | +}; |
| 231 | + |
| 232 | +class Solution { |
| 233 | +public: |
| 234 | + vector<int> leftmostBuildingQueries(vector<int>& heights, vector<vector<int>>& queries) { |
| 235 | + int n = heights.size(), m = queries.size(); |
| 236 | + for (auto& q : queries) { |
| 237 | + if (q[0] > q[1]) { |
| 238 | + swap(q[0], q[1]); |
| 239 | + } |
| 240 | + } |
| 241 | + vector<int> idx(m); |
| 242 | + iota(idx.begin(), idx.end(), 0); |
| 243 | + sort(idx.begin(), idx.end(), [&](int i, int j) { |
| 244 | + return queries[j][1] < queries[i][1]; |
| 245 | + }); |
| 246 | + vector<int> s = heights; |
| 247 | + sort(s.begin(), s.end()); |
| 248 | + s.erase(unique(s.begin(), s.end()), s.end()); |
| 249 | + vector<int> ans(m); |
| 250 | + int j = n - 1; |
| 251 | + BinaryIndexedTree tree(n); |
| 252 | + for (int i : idx) { |
| 253 | + int l = queries[i][0], r = queries[i][1]; |
| 254 | + while (j > r) { |
| 255 | + int k = s.end() - lower_bound(s.begin(), s.end(), heights[j]) + 1; |
| 256 | + tree.update(k, j); |
| 257 | + --j; |
| 258 | + } |
| 259 | + if (l == r || heights[l] < heights[r]) { |
| 260 | + ans[i] = r; |
| 261 | + } else { |
| 262 | + int k = s.end() - lower_bound(s.begin(), s.end(), heights[l]); |
| 263 | + ans[i] = tree.query(k); |
| 264 | + } |
| 265 | + } |
| 266 | + return ans; |
| 267 | + } |
| 268 | +}; |
85 | 269 | ```
|
86 | 270 |
|
87 | 271 | ### **Go**
|
88 | 272 |
|
89 | 273 | ```go
|
| 274 | +const inf int = 1 << 30 |
| 275 | +
|
| 276 | +type BinaryIndexedTree struct { |
| 277 | + n int |
| 278 | + c []int |
| 279 | +} |
| 280 | +
|
| 281 | +func NewBinaryIndexedTree(n int) BinaryIndexedTree { |
| 282 | + c := make([]int, n+1) |
| 283 | + for i := range c { |
| 284 | + c[i] = inf |
| 285 | + } |
| 286 | + return BinaryIndexedTree{n: n, c: c} |
| 287 | +} |
| 288 | +
|
| 289 | +func (bit *BinaryIndexedTree) update(x, v int) { |
| 290 | + for x <= bit.n { |
| 291 | + bit.c[x] = min(bit.c[x], v) |
| 292 | + x += x & -x |
| 293 | + } |
| 294 | +} |
| 295 | +
|
| 296 | +func (bit *BinaryIndexedTree) query(x int) int { |
| 297 | + mi := inf |
| 298 | + for x > 0 { |
| 299 | + mi = min(mi, bit.c[x]) |
| 300 | + x -= x & -x |
| 301 | + } |
| 302 | + if mi == inf { |
| 303 | + return -1 |
| 304 | + } |
| 305 | + return mi |
| 306 | +} |
| 307 | +
|
| 308 | +func leftmostBuildingQueries(heights []int, queries [][]int) []int { |
| 309 | + n, m := len(heights), len(queries) |
| 310 | + for _, q := range queries { |
| 311 | + if q[0] > q[1] { |
| 312 | + q[0], q[1] = q[1], q[0] |
| 313 | + } |
| 314 | + } |
| 315 | + idx := make([]int, m) |
| 316 | + for i := range idx { |
| 317 | + idx[i] = i |
| 318 | + } |
| 319 | + sort.Slice(idx, func(i, j int) bool { return queries[idx[j]][1] < queries[idx[i]][1] }) |
| 320 | + s := make([]int, n) |
| 321 | + copy(s, heights) |
| 322 | + sort.Ints(s) |
| 323 | + ans := make([]int, m) |
| 324 | + tree := NewBinaryIndexedTree(n) |
| 325 | + j := n - 1 |
| 326 | + for _, i := range idx { |
| 327 | + l, r := queries[i][0], queries[i][1] |
| 328 | + for ; j > r; j-- { |
| 329 | + k := n - sort.SearchInts(s, heights[j]) + 1 |
| 330 | + tree.update(k, j) |
| 331 | + } |
| 332 | + if l == r || heights[l] < heights[r] { |
| 333 | + ans[i] = r |
| 334 | + } else { |
| 335 | + k := n - sort.SearchInts(s, heights[l]) |
| 336 | + ans[i] = tree.query(k) |
| 337 | + } |
| 338 | + } |
| 339 | + return ans |
| 340 | +} |
| 341 | +``` |
90 | 342 |
|
| 343 | +### **TypeScript** |
| 344 | + |
| 345 | +```ts |
| 346 | +class BinaryIndexedTree { |
| 347 | + private n: number; |
| 348 | + private c: number[]; |
| 349 | + private inf: number = 1 << 30; |
| 350 | + |
| 351 | + constructor(n: number) { |
| 352 | + this.n = n; |
| 353 | + this.c = Array(n + 1).fill(this.inf); |
| 354 | + } |
| 355 | + |
| 356 | + update(x: number, v: number): void { |
| 357 | + while (x <= this.n) { |
| 358 | + this.c[x] = Math.min(this.c[x], v); |
| 359 | + x += x & -x; |
| 360 | + } |
| 361 | + } |
| 362 | + |
| 363 | + query(x: number): number { |
| 364 | + let mi = this.inf; |
| 365 | + while (x > 0) { |
| 366 | + mi = Math.min(mi, this.c[x]); |
| 367 | + x -= x & -x; |
| 368 | + } |
| 369 | + return mi === this.inf ? -1 : mi; |
| 370 | + } |
| 371 | +} |
| 372 | + |
| 373 | +function leftmostBuildingQueries(heights: number[], queries: number[][]): number[] { |
| 374 | + const n = heights.length; |
| 375 | + const m = queries.length; |
| 376 | + for (const q of queries) { |
| 377 | + if (q[0] > q[1]) { |
| 378 | + [q[0], q[1]] = [q[1], q[0]]; |
| 379 | + } |
| 380 | + } |
| 381 | + const idx: number[] = Array(m) |
| 382 | + .fill(0) |
| 383 | + .map((_, i) => i); |
| 384 | + idx.sort((i, j) => queries[j][1] - queries[i][1]); |
| 385 | + const tree = new BinaryIndexedTree(n); |
| 386 | + const ans: number[] = Array(m).fill(-1); |
| 387 | + const s = [...heights]; |
| 388 | + s.sort((a, b) => a - b); |
| 389 | + const search = (x: number) => { |
| 390 | + let [l, r] = [0, n]; |
| 391 | + while (l < r) { |
| 392 | + const mid = (l + r) >> 1; |
| 393 | + if (s[mid] >= x) { |
| 394 | + r = mid; |
| 395 | + } else { |
| 396 | + l = mid + 1; |
| 397 | + } |
| 398 | + } |
| 399 | + return l; |
| 400 | + }; |
| 401 | + let j = n - 1; |
| 402 | + for (const i of idx) { |
| 403 | + const [l, r] = queries[i]; |
| 404 | + while (j > r) { |
| 405 | + const k = n - search(heights[j]) + 1; |
| 406 | + tree.update(k, j); |
| 407 | + --j; |
| 408 | + } |
| 409 | + if (l === r || heights[l] < heights[r]) { |
| 410 | + ans[i] = r; |
| 411 | + } else { |
| 412 | + const k = n - search(heights[l]); |
| 413 | + ans[i] = tree.query(k); |
| 414 | + } |
| 415 | + } |
| 416 | + return ans; |
| 417 | +} |
91 | 418 | ```
|
92 | 419 |
|
93 | 420 | ### **...**
|
|
0 commit comments