package class_2022_07_2_week; import java.util.Arrays; // 我们给出了一个(轴对齐的)二维矩形列表 rectangles 。 // 对于 rectangle[i] = [x1, y1, x2, y2],其中(x1,y1)是矩形 i 左下角的坐标 // (xi1, yi1) 是该矩形 左下角 的坐标, (xi2, yi2) 是该矩形 右上角 的坐标。 // 计算平面中所有 rectangles 所覆盖的 总面积 。 // 任何被两个或多个矩形覆盖的区域应只计算 一次 。 // 返回 总面积 。因为答案可能太大,返回 10^9 + 7 的 模 。 // 本题测试链接 : https://leetcode.cn/problems/rectangle-area-ii/ public class Code05_LineSweepAlgorithm1 { // x y public static int rectangleArea(int[][] rectangles) { int n = rectangles.length; long[][] arr = new long[n << 1][4]; long max = 0; for (int i = 0; i < n; i++) { // x1 y1 左下角点的坐标 // x2 y2 右上角点的坐标 // 解释一下y1为啥要+1 // 比如y1 = 3, y2 = 7 // 实际的处理的时候,真实的线段认为是闭区间[4,7]的 // 如果不这么处理会有问题 // 比如先在y1 = 3, y2 = 7上,都+1 // 那么此时: // value: 0 0 1 1 1 1 1 0 // index: 1 2 3 4 5 6 7 8 // 这是不对的! // 因为线段[3,7]长度是4啊!而在线段树里,是5个1! // 所以,y1 = 3, y2 = 7 // 我们就是认为是4~7,都+1 // 那么此时: // value: 0 0 0 1 1 1 1 0 // index: 1 2 3 4 5 6 7 8 // 线段树上,正好4个1,和我们想要的距离是一致的 int x1 = rectangles[i][0]; int y1 = rectangles[i][1] + 1; int x2 = rectangles[i][2]; int y2 = rectangles[i][3]; arr[i][0] = x1; arr[i][1] = y1; arr[i][2] = y2; arr[i][3] = 1; arr[i + n][0] = x2; arr[i + n][1] = y1; arr[i + n][2] = y2; arr[i + n][3] = -1; max = Math.max(max, y2); } return coverArea(arr, n << 1, max); } public static int coverArea(long[][] arr, int n, long max) { // 所有的事件,都在arr里 // [x, y1, y2, +1/-1] // 早 -> 晚 Arrays.sort(arr, 0, n, (a, b) -> a[0] <= b[0] ? -1 : 1); // max y的值,可能的最大值,非常大也支持! DynamicSegmentTree dst = new DynamicSegmentTree(max); long preX = 0; long ans = 0; for (int i = 0; i < n; i++) { // dst.query() : 开点线段树告诉你!y方向真实的长度! ans += dst.query() * (arr[i][0] - preX); ans %= 1000000007; preX = arr[i][0]; dst.add(arr[i][1], arr[i][2], arr[i][3]); } return (int) ans; } public static class Node { public long cover; public long len; public Node left; public Node right; } public static class DynamicSegmentTree { public Node root; public long size; public DynamicSegmentTree(long max) { root = new Node(); size = max; } public void add(long L, long R, long cover) { add(root, 1, size, L, R, cover); } private void add(Node cur, long l, long r, long L, long R, long cover) { if (L <= l && R >= r) { cur.cover += cover; } else { if (cur.left == null) { cur.left = new Node(); } if (cur.right == null) { cur.right = new Node(); } long m = l + ((r - l) >> 1); if (L <= m) { add(cur.left, l, m, L, R, cover); } if (R > m) { add(cur.right, m + 1, r, L, R, cover); } } pushUp(cur, l, r); } private void pushUp(Node cur, long l, long r) { if (cur.cover > 0) { cur.len = r - l + 1; } else { cur.len = (cur.left != null ? cur.left.len : 0) + (cur.right != null ? cur.right.len : 0); } } public long query() { return root.len; } } }