1
1
package g3401_3500 .s3454_separate_squares_ii ;
2
2
3
- // #Hard #2025_02_16_Time_243_ms_ (100.00%)_Space_76.06_MB_ (100.00%)
3
+ // #Hard #2025_02_16_Time_246_ms_ (100.00%)_Space_79.98_MB_ (100.00%)
4
4
5
5
import java .util .Arrays ;
6
6
import java .util .Comparator ;
@@ -9,86 +9,99 @@ public class Solution {
9
9
public double separateSquares (int [][] squares ) {
10
10
int n = squares .length ;
11
11
int m = 2 * n ;
12
+ Event [] events = createEvents (squares , m );
13
+ double [] xsRaw = createXsRaw (squares , m );
14
+ Arrays .sort (events , Comparator .comparingDouble (e -> e .y ));
15
+ double [] xs = compress (xsRaw );
16
+ double totalUnionArea = calculateTotalUnionArea (events , xs , m );
17
+ double target = totalUnionArea / 2.0 ;
18
+ return findSplitPoint (events , xs , m , target );
19
+ }
20
+
21
+ private Event [] createEvents (int [][] squares , int m ) {
12
22
Event [] events = new Event [m ];
13
- double [] xsRaw = new double [m ];
14
23
int idx = 0 ;
15
- int xIdx = 0 ;
16
24
for (int [] sq : squares ) {
17
- // Each square gives a rectangle [x, x+l] x [y, y+l]
18
25
double x = sq [0 ];
19
26
double y = sq [1 ];
20
27
double l = sq [2 ];
21
28
double x2 = x + l ;
22
29
double y2 = y + l ;
23
30
events [idx ++] = new Event (y , x , x2 , 1 );
24
31
events [idx ++] = new Event (y2 , x , x2 , -1 );
32
+ }
33
+ return events ;
34
+ }
35
+
36
+ private double [] createXsRaw (int [][] squares , int m ) {
37
+ double [] xsRaw = new double [m ];
38
+ int xIdx = 0 ;
39
+ for (int [] sq : squares ) {
40
+ double x = sq [0 ];
41
+ double l = sq [2 ];
25
42
xsRaw [xIdx ++] = x ;
26
- xsRaw [xIdx ++] = x2 ;
43
+ xsRaw [xIdx ++] = x + l ;
27
44
}
28
- // Sort events by their y-coordinate (they are exact integers in double format)
29
- Arrays .sort (events , Comparator .comparingDouble (e -> e .y ));
30
- // Compress x-coordinates
31
- double [] xs = compress (xsRaw );
32
- // FIRST SWEEP: compute total union area.
45
+ return xsRaw ;
46
+ }
47
+
48
+ private double calculateTotalUnionArea (Event [] events , double [] xs , int m ) {
33
49
SegmentTree segTree = new SegmentTree (xs );
34
50
double totalUnionArea = 0.0 ;
35
51
double lastY = events [0 ].y ;
36
- for (int i = 0 ; i < m ; ) {
52
+ int i = 0 ;
53
+ while (i < m ) {
37
54
double curY = events [i ].y ;
38
55
if (curY > lastY ) {
39
56
double unionX = segTree .query ();
40
57
totalUnionArea += unionX * (curY - lastY );
41
58
lastY = curY ;
42
59
}
43
- // Process all events at y == curY
44
60
while (i < m && events [i ].y == curY ) {
45
- int lIdx = Arrays .binarySearch (xs , events [i ].x1 );
46
- if (lIdx < 0 ) {
47
- lIdx = -lIdx - 1 ;
48
- }
49
- int rIdx = Arrays .binarySearch (xs , events [i ].x2 );
50
- if (rIdx < 0 ) {
51
- rIdx = -rIdx - 1 ;
52
- }
53
- segTree .update (1 , 0 , xs .length - 1 , lIdx , rIdx , events [i ].type );
61
+ int [] indices = findIndices (xs , events [i ]);
62
+ segTree .update (1 , 0 , xs .length - 1 , indices [0 ], indices [1 ], events [i ].type );
54
63
i ++;
55
64
}
56
65
}
57
- double target = totalUnionArea / 2.0 ;
58
- // SECOND SWEEP: find minimal y such that cumulative union area reaches target.
59
- // Reinitialize segment tree for a fresh sweep.
60
- segTree = new SegmentTree (xs );
61
- lastY = events [0 ].y ;
66
+ return totalUnionArea ;
67
+ }
68
+
69
+ private double findSplitPoint (Event [] events , double [] xs , int m , double target ) {
70
+ SegmentTree segTree = new SegmentTree (xs );
71
+ double lastY = events [0 ].y ;
62
72
double cumArea = 0.0 ;
63
73
for (int i = 0 ; i < m ; ) {
64
74
double curY = events [i ].y ;
65
75
if (curY > lastY ) {
66
76
double unionX = segTree .query ();
67
77
double dy = curY - lastY ;
68
78
if (cumArea + unionX * dy >= target - 1e-10 ) {
69
- // The answer lies in this interval.
70
79
return lastY + (target - cumArea ) / unionX ;
71
80
}
72
81
cumArea += unionX * dy ;
73
82
lastY = curY ;
74
83
}
75
84
while (i < m && events [i ].y == curY ) {
76
- int lIdx = Arrays .binarySearch (xs , events [i ].x1 );
77
- if (lIdx < 0 ) {
78
- lIdx = -lIdx - 1 ;
79
- }
80
- int rIdx = Arrays .binarySearch (xs , events [i ].x2 );
81
- if (rIdx < 0 ) {
82
- rIdx = -rIdx - 1 ;
83
- }
84
- segTree .update (1 , 0 , xs .length - 1 , lIdx , rIdx , events [i ].type );
85
+ int [] indices = findIndices (xs , events [i ]);
86
+ segTree .update (1 , 0 , xs .length - 1 , indices [0 ], indices [1 ], events [i ].type );
85
87
i ++;
86
88
}
87
89
}
88
90
return lastY ;
89
91
}
90
92
91
- // Compress an array of doubles into a sorted array of unique values.
93
+ private int [] findIndices (double [] xs , Event event ) {
94
+ int lIdx = Arrays .binarySearch (xs , event .x1 );
95
+ if (lIdx < 0 ) {
96
+ lIdx = -lIdx - 1 ;
97
+ }
98
+ int rIdx = Arrays .binarySearch (xs , event .x2 );
99
+ if (rIdx < 0 ) {
100
+ rIdx = -rIdx - 1 ;
101
+ }
102
+ return new int [] {lIdx , rIdx };
103
+ }
104
+
92
105
private double [] compress (double [] arr ) {
93
106
Arrays .sort (arr );
94
107
int cnt = 1 ;
@@ -108,12 +121,10 @@ private double[] compress(double[] arr) {
108
121
return res ;
109
122
}
110
123
111
- // Event class for the sweep-line.
112
124
private static class Event {
113
125
double y ;
114
126
double x1 ;
115
127
double x2 ;
116
- // +1 for adding an interval; -1 for removing.
117
128
int type ;
118
129
119
130
Event (double y , double x1 , double x2 , int type ) {
@@ -124,26 +135,19 @@ private static class Event {
124
135
}
125
136
}
126
137
127
- // Segment Tree for maintaining the union length over the x-axis.
128
138
private static class SegmentTree {
129
139
int n ;
130
- // Covered length of the segment.
131
140
double [] tree ;
132
- // Coverage count for the segment.
133
141
int [] count ;
134
- // The compressed x-coordinates.
135
142
double [] xs ;
136
143
137
144
SegmentTree (double [] xs ) {
138
145
this .xs = xs ;
139
146
this .n = xs .length ;
140
- // Allocate 4*n size arrays.
141
147
tree = new double [4 * n ];
142
148
count = new int [4 * n ];
143
149
}
144
150
145
- // Update the range [ql, qr) with value 'val'.
146
- // The current node covers indices [l, r) in xs.
147
151
void update (int idx , int l , int r , int ql , int qr , int val ) {
148
152
if (qr <= l || ql >= r ) {
149
153
return ;
@@ -164,7 +168,6 @@ void update(int idx, int l, int r, int ql, int qr, int val) {
164
168
}
165
169
}
166
170
167
- // Query the current total union length.
168
171
double query () {
169
172
return tree [1 ];
170
173
}
0 commit comments