|
| 1 | +# Time: O(logn) |
| 2 | +# Space: O(n) |
| 3 | + |
| 4 | +# We are given a list of (axis-aligned) rectangles. |
| 5 | +# Each rectangle[i] = [x1, y1, x2, y2] , |
| 6 | +# where (x1, y1) are the coordinates of the bottom-left corner, |
| 7 | +# and (x2, y2) are the coordinates of the top-right corner of |
| 8 | +# the ith rectangle. |
| 9 | +# |
| 10 | +# Find the total area covered by all rectangles in the plane. |
| 11 | +# Since the answer may be too large, return it modulo 10^9 + 7. |
| 12 | +# |
| 13 | +# Example 1: |
| 14 | +# |
| 15 | +# Input: [[0,0,2,2],[1,0,2,3],[1,0,3,1]] |
| 16 | +# Output: 6 |
| 17 | +# Explanation: As illustrated in the picture. |
| 18 | +# Example 2: |
| 19 | +# |
| 20 | +# Input: [[0,0,1000000000,1000000000]] |
| 21 | +# Output: 49 |
| 22 | +# Explanation: The answer is 10^18 modulo (10^9 + 7), |
| 23 | +# which is (10^9)^2 = (-7)^2 = 49. |
| 24 | +# |
| 25 | +# Note: |
| 26 | +# - 1 <= rectangles.length <= 200 |
| 27 | +# - rectanges[i].length = 4 |
| 28 | +# - 0 <= rectangles[i][j] <= 10^9 |
| 29 | +# - The total area covered by all rectangles will never exceed 2^63 - 1 and |
| 30 | +# thus will fit in a 64-bit signed integer. |
| 31 | + |
| 32 | + |
| 33 | +class SegmentTreeNode(object): |
| 34 | + def __init__(self, start, end): |
| 35 | + self.start, self.end = start, end |
| 36 | + self.total = self.count = 0 |
| 37 | + self._left = self._right = None |
| 38 | + |
| 39 | + def mid(self): |
| 40 | + return (self.start+self.end) // 2 |
| 41 | + |
| 42 | + def left(self): |
| 43 | + self._left = self._left or SegmentTreeNode(self.start, self.mid()) |
| 44 | + return self._left |
| 45 | + |
| 46 | + def right(self): |
| 47 | + self._right = self._right or SegmentTreeNode(self.mid(), self.end) |
| 48 | + return self._right |
| 49 | + |
| 50 | + def update(self, X, i, j, val): |
| 51 | + if i >= j: |
| 52 | + return 0 |
| 53 | + if self.start == i and self.end == j: |
| 54 | + self.count += val |
| 55 | + else: |
| 56 | + self.left().update(X, i, min(self.mid(), j), val) |
| 57 | + self.right().update(X, max(self.mid(), i), j, val) |
| 58 | + if self.count > 0: |
| 59 | + self.total = X[self.end]-X[self.start] |
| 60 | + else: |
| 61 | + self.total = self.left().total + self.right().total |
| 62 | + return self.total |
| 63 | + |
| 64 | + |
| 65 | +class Solution(object): |
| 66 | + def rectangleArea(self, rectangles): |
| 67 | + """ |
| 68 | + :type rectangles: List[List[int]] |
| 69 | + :rtype: int |
| 70 | + """ |
| 71 | + OPEN, CLOSE = 1, -1 |
| 72 | + events = [] |
| 73 | + X = set() |
| 74 | + for x1, y1, x2, y2 in rectangles: |
| 75 | + events.append((y1, OPEN, x1, x2)) |
| 76 | + events.append((y2, CLOSE, x1, x2)) |
| 77 | + X.add(x1) |
| 78 | + X.add(x2) |
| 79 | + events.sort() |
| 80 | + X = sorted(X) |
| 81 | + Xi = {x: i for i, x in enumerate(X)} |
| 82 | + |
| 83 | + st = SegmentTreeNode(0, len(X)-1) |
| 84 | + result = 0 |
| 85 | + cur_x_sum = 0 |
| 86 | + cur_y = events[0][0] |
| 87 | + for y, typ, x1, x2 in events: |
| 88 | + result += cur_x_sum * (y-cur_y) |
| 89 | + cur_x_sum = st.update(X, Xi[x1], Xi[x2], typ) |
| 90 | + cur_y = y |
| 91 | + return result % (10**9+7) |
0 commit comments