11package g3401_3500 .s3454_separate_squares_ii ;
22
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%)
44
55import java .util .Arrays ;
66import java .util .Comparator ;
@@ -9,86 +9,99 @@ public class Solution {
99 public double separateSquares (int [][] squares ) {
1010 int n = squares .length ;
1111 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 ) {
1222 Event [] events = new Event [m ];
13- double [] xsRaw = new double [m ];
1423 int idx = 0 ;
15- int xIdx = 0 ;
1624 for (int [] sq : squares ) {
17- // Each square gives a rectangle [x, x+l] x [y, y+l]
1825 double x = sq [0 ];
1926 double y = sq [1 ];
2027 double l = sq [2 ];
2128 double x2 = x + l ;
2229 double y2 = y + l ;
2330 events [idx ++] = new Event (y , x , x2 , 1 );
2431 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 ];
2542 xsRaw [xIdx ++] = x ;
26- xsRaw [xIdx ++] = x2 ;
43+ xsRaw [xIdx ++] = x + l ;
2744 }
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 ) {
3349 SegmentTree segTree = new SegmentTree (xs );
3450 double totalUnionArea = 0.0 ;
3551 double lastY = events [0 ].y ;
36- for (int i = 0 ; i < m ; ) {
52+ int i = 0 ;
53+ while (i < m ) {
3754 double curY = events [i ].y ;
3855 if (curY > lastY ) {
3956 double unionX = segTree .query ();
4057 totalUnionArea += unionX * (curY - lastY );
4158 lastY = curY ;
4259 }
43- // Process all events at y == curY
4460 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 );
5463 i ++;
5564 }
5665 }
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 ;
6272 double cumArea = 0.0 ;
6373 for (int i = 0 ; i < m ; ) {
6474 double curY = events [i ].y ;
6575 if (curY > lastY ) {
6676 double unionX = segTree .query ();
6777 double dy = curY - lastY ;
6878 if (cumArea + unionX * dy >= target - 1e-10 ) {
69- // The answer lies in this interval.
7079 return lastY + (target - cumArea ) / unionX ;
7180 }
7281 cumArea += unionX * dy ;
7382 lastY = curY ;
7483 }
7584 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 );
8587 i ++;
8688 }
8789 }
8890 return lastY ;
8991 }
9092
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+
92105 private double [] compress (double [] arr ) {
93106 Arrays .sort (arr );
94107 int cnt = 1 ;
@@ -108,12 +121,10 @@ private double[] compress(double[] arr) {
108121 return res ;
109122 }
110123
111- // Event class for the sweep-line.
112124 private static class Event {
113125 double y ;
114126 double x1 ;
115127 double x2 ;
116- // +1 for adding an interval; -1 for removing.
117128 int type ;
118129
119130 Event (double y , double x1 , double x2 , int type ) {
@@ -124,26 +135,19 @@ private static class Event {
124135 }
125136 }
126137
127- // Segment Tree for maintaining the union length over the x-axis.
128138 private static class SegmentTree {
129139 int n ;
130- // Covered length of the segment.
131140 double [] tree ;
132- // Coverage count for the segment.
133141 int [] count ;
134- // The compressed x-coordinates.
135142 double [] xs ;
136143
137144 SegmentTree (double [] xs ) {
138145 this .xs = xs ;
139146 this .n = xs .length ;
140- // Allocate 4*n size arrays.
141147 tree = new double [4 * n ];
142148 count = new int [4 * n ];
143149 }
144150
145- // Update the range [ql, qr) with value 'val'.
146- // The current node covers indices [l, r) in xs.
147151 void update (int idx , int l , int r , int ql , int qr , int val ) {
148152 if (qr <= l || ql >= r ) {
149153 return ;
@@ -164,7 +168,6 @@ void update(int idx, int l, int r, int ql, int qr, int val) {
164168 }
165169 }
166170
167- // Query the current total union length.
168171 double query () {
169172 return tree [1 ];
170173 }
0 commit comments