Welcome to Subscribe On Youtube

3454. Separate Squares II

Description

You are given a 2D integer array squares. Each squares[i] = [xi, yi, li] represents the coordinates of the bottom-left point and the side length of a square parallel to the x-axis.

Find the minimum y-coordinate value of a horizontal line such that the total area covered by squares above the line equals the total area covered by squares below the line.

Answers within 10-5 of the actual answer will be accepted.

Note: Squares may overlap. Overlapping areas should be counted only once in this version.

 

Example 1:

Input: squares = [[0,0,1],[2,2,1]]

Output: 1.00000

Explanation:

Any horizontal line between y = 1 and y = 2 results in an equal split, with 1 square unit above and 1 square unit below. The minimum y-value is 1.

Example 2:

Input: squares = [[0,0,2],[1,1,1]]

Output: 1.00000

Explanation:

Since the blue square overlaps with the red square, it will not be counted again. Thus, the line y = 1 splits the squares into two equal parts.

 

Constraints:

  • 1 <= squares.length <= 5 * 104
  • squares[i] = [xi, yi, li]
  • squares[i].length == 3
  • 0 <= xi, yi <= 109
  • 1 <= li <= 109
  • The total area of all the squares will not exceed 1015.

Solutions

Solution 1

  • class Node {
        int l, r, cnt, length;
    }
    
    class SegmentTree {
        private Node[] tr;
        private int[] nums;
    
        public SegmentTree(int[] nums) {
            this.nums = nums;
            int n = nums.length - 1;
            tr = new Node[n << 2];
            for (int i = 0; i < tr.length; ++i) {
                tr[i] = new Node();
            }
            build(1, 0, n - 1);
        }
    
        private void build(int u, int l, int r) {
            tr[u].l = l;
            tr[u].r = r;
            if (l != r) {
                int mid = (l + r) >> 1;
                build(u << 1, l, mid);
                build(u << 1 | 1, mid + 1, r);
            }
        }
    
        public void modify(int u, int l, int r, int k) {
            if (tr[u].l >= l && tr[u].r <= r) {
                tr[u].cnt += k;
            } else {
                int mid = (tr[u].l + tr[u].r) >> 1;
                if (l <= mid) {
                    modify(u << 1, l, r, k);
                }
                if (r > mid) {
                    modify(u << 1 | 1, l, r, k);
                }
            }
            pushup(u);
        }
    
        private void pushup(int u) {
            if (tr[u].cnt > 0) {
                tr[u].length = nums[tr[u].r + 1] - nums[tr[u].l];
            } else if (tr[u].l == tr[u].r) {
                tr[u].length = 0;
            } else {
                tr[u].length = tr[u << 1].length + tr[u << 1 | 1].length;
            }
        }
    
        public int query() {
            return tr[1].length;
        }
    }
    
    class Solution {
        public double separateSquares(int[][] squares) {
            Set<Integer> xs = new HashSet<>();
            List<int[]> segs = new ArrayList<>();
            for (int[] sq : squares) {
                int x1 = sq[0], y1 = sq[1], l = sq[2];
                int x2 = x1 + l, y2 = y1 + l;
                xs.add(x1);
                xs.add(x2);
                segs.add(new int[] {y1, x1, x2, 1});
                segs.add(new int[] {y2, x1, x2, -1});
            }
            segs.sort(Comparator.comparingInt(a -> a[0]));
            int[] st = new int[xs.size()];
            int i = 0;
            for (int x : xs) {
                st[i++] = x;
            }
            Arrays.sort(st);
            SegmentTree tree = new SegmentTree(st);
            Map<Integer, Integer> d = new HashMap<>(st.length);
            for (i = 0; i < st.length; i++) {
                d.put(st[i], i);
            }
            double area = 0.0;
            int y0 = 0;
            for (int[] s : segs) {
                int y = s[0], x1 = s[1], x2 = s[2], k = s[3];
                area += (double) (y - y0) * tree.query();
                tree.modify(1, d.get(x1), d.get(x2) - 1, k);
                y0 = y;
            }
            double target = area / 2.0;
            area = 0.0;
            y0 = 0;
            for (int[] s : segs) {
                int y = s[0], x1 = s[1], x2 = s[2], k = s[3];
                double t = (double) (y - y0) * tree.query();
                if (area + t >= target) {
                    return y0 + (target - area) / tree.query();
                }
                area += t;
                tree.modify(1, d.get(x1), d.get(x2) - 1, k);
                y0 = y;
            }
            return 0.0;
        }
    }
    
    
  • struct Node {
        int l = 0, r = 0, cnt = 0;
        int length = 0;
    };
    
    class SegmentTree {
    private:
        vector<Node> tr;
        vector<int> nums;
    
        void build(int u, int l, int r) {
            tr[u].l = l;
            tr[u].r = r;
            if (l != r) {
                int mid = (l + r) >> 1;
                build(u << 1, l, mid);
                build(u << 1 | 1, mid + 1, r);
            }
        }
    
        void pushup(int u) {
            if (tr[u].cnt > 0) {
                tr[u].length = nums[tr[u].r + 1] - nums[tr[u].l];
            } else if (tr[u].l == tr[u].r) {
                tr[u].length = 0;
            } else {
                tr[u].length = tr[u << 1].length + tr[u << 1 | 1].length;
            }
        }
    
    public:
        SegmentTree(const vector<int>& nums)
            : nums(nums) {
            int n = (int) nums.size() - 1;
            tr.assign(n << 2, Node());
            build(1, 0, n - 1);
        }
    
        void modify(int u, int l, int r, int k) {
            if (tr[u].l >= l && tr[u].r <= r) {
                tr[u].cnt += k;
            } else {
                int mid = (tr[u].l + tr[u].r) >> 1;
                if (l <= mid) modify(u << 1, l, r, k);
                if (r > mid) modify(u << 1 | 1, l, r, k);
            }
            pushup(u);
        }
    
        int query() const {
            return tr[1].length;
        }
    };
    
    class Solution {
    public:
        double separateSquares(vector<vector<int>>& squares) {
            set<int> xs;
            vector<array<int, 4>> segs;
    
            for (auto& sq : squares) {
                int x1 = sq[0], y1 = sq[1], l = sq[2];
                int x2 = x1 + l, y2 = y1 + l;
                xs.insert(x1);
                xs.insert(x2);
                segs.push_back({y1, x1, x2, 1});
                segs.push_back({y2, x1, x2, -1});
            }
    
            sort(segs.begin(), segs.end(), [](const auto& a, const auto& b) {
                return a[0] < b[0];
            });
    
            vector<int> st;
            st.reserve(xs.size());
            for (int x : xs) st.push_back(x);
    
            SegmentTree tree(st);
    
            unordered_map<int, int> d;
            d.reserve(st.size() * 2);
            for (int i = 0; i < (int) st.size(); i++) d[st[i]] = i;
    
            double area = 0.0;
            int y0 = 0;
            for (auto& s : segs) {
                int y = s[0], x1 = s[1], x2 = s[2], k = s[3];
                area += (double) (y - y0) * tree.query();
                tree.modify(1, d[x1], d[x2] - 1, k);
                y0 = y;
            }
    
            double target = area / 2.0;
            area = 0.0;
            y0 = 0;
            for (auto& s : segs) {
                int y = s[0], x1 = s[1], x2 = s[2], k = s[3];
                double t = (double) (y - y0) * tree.query();
                if (area + t >= target) {
                    return y0 + (target - area) / tree.query();
                }
                area += t;
                tree.modify(1, d[x1], d[x2] - 1, k);
                y0 = y;
            }
    
            return 0.0;
        }
    };
    
    
  • class Node:
        __slots__ = ("l", "r", "cnt", "length")
    
        def __init__(self):
            self.l = self.r = 0
            self.cnt = self.length = 0
    
    
    class SegmentTree:
        def __init__(self, nums):
            n = len(nums) - 1
            self.nums = nums
            self.tr = [Node() for _ in range(n << 2)]
            self.build(1, 0, n - 1)
    
        def build(self, u, l, r):
            self.tr[u].l, self.tr[u].r = l, r
            if l != r:
                mid = (l + r) >> 1
                self.build(u << 1, l, mid)
                self.build(u << 1 | 1, mid + 1, r)
    
        def modify(self, u, l, r, k):
            if self.tr[u].l >= l and self.tr[u].r <= r:
                self.tr[u].cnt += k
            else:
                mid = (self.tr[u].l + self.tr[u].r) >> 1
                if l <= mid:
                    self.modify(u << 1, l, r, k)
                if r > mid:
                    self.modify(u << 1 | 1, l, r, k)
            self.pushup(u)
    
        def pushup(self, u):
            if self.tr[u].cnt:
                self.tr[u].length = self.nums[self.tr[u].r + 1] - self.nums[self.tr[u].l]
            elif self.tr[u].l == self.tr[u].r:
                self.tr[u].length = 0
            else:
                self.tr[u].length = self.tr[u << 1].length + self.tr[u << 1 | 1].length
    
        @property
        def length(self):
            return self.tr[1].length
    
    
    class Solution:
        def separateSquares(self, squares: List[List[int]]) -> float:
            xs = set()
            segs = []
            for x1, y1, l in squares:
                x2, y2 = x1 + l, y1 + l
                xs.update([x1, x2])
                segs.append((y1, x1, x2, 1))
                segs.append((y2, x1, x2, -1))
            segs.sort()
            st = sorted(xs)
            tree = SegmentTree(st)
            d = {x: i for i, x in enumerate(st)}
            area = 0
            y0 = 0
            for y, x1, x2, k in segs:
                area += (y - y0) * tree.length
                tree.modify(1, d[x1], d[x2] - 1, k)
                y0 = y
    
            target = area / 2
            area = 0
            y0 = 0
            for y, x1, x2, k in segs:
                t = (y - y0) * tree.length
                if area + t >= target:
                    return y0 + (target - area) / tree.length
                area += t
                tree.modify(1, d[x1], d[x2] - 1, k)
                y0 = y
            return 0
    
    
  • type Node struct {
    	l, r   int
    	cnt    int
    	length int
    }
    
    type SegmentTree struct {
    	tr   []Node
    	nums []int
    }
    
    func NewSegmentTree(nums []int) *SegmentTree {
    	n := len(nums) - 1
    	tr := make([]Node, n<<2)
    	t := &SegmentTree{tr: tr, nums: nums}
    	t.build(1, 0, n-1)
    	return t
    }
    
    func (t *SegmentTree) build(u, l, r int) {
    	t.tr[u].l = l
    	t.tr[u].r = r
    	if l != r {
    		mid := (l + r) >> 1
    		t.build(u<<1, l, mid)
    		t.build(u<<1|1, mid+1, r)
    	}
    }
    
    func (t *SegmentTree) modify(u, l, r, k int) {
    	if l > r {
    		return
    	}
    	if t.tr[u].l >= l && t.tr[u].r <= r {
    		t.tr[u].cnt += k
    	} else {
    		mid := (t.tr[u].l + t.tr[u].r) >> 1
    		if l <= mid {
    			t.modify(u<<1, l, r, k)
    		}
    		if r > mid {
    			t.modify(u<<1|1, l, r, k)
    		}
    	}
    	t.pushup(u)
    }
    
    func (t *SegmentTree) pushup(u int) {
    	if t.tr[u].cnt > 0 {
    		t.tr[u].length = t.nums[t.tr[u].r+1] - t.nums[t.tr[u].l]
    	} else if t.tr[u].l == t.tr[u].r {
    		t.tr[u].length = 0
    	} else {
    		t.tr[u].length = t.tr[u<<1].length + t.tr[u<<1|1].length
    	}
    }
    
    func (t *SegmentTree) query() int {
    	return t.tr[1].length
    }
    
    func separateSquares(squares [][]int) float64 {
    	pos := make(map[int]bool)
    	xs := make([]int, 0)
    	segs := make([][]int, 0, len(squares)*2)
    	for _, sq := range squares {
    		x1, y1, l := sq[0], sq[1], sq[2]
    		x2, y2 := x1+l, y1+l
    		if !pos[x1] {
    			pos[x1] = true
    			xs = append(xs, x1)
    		}
    		if !pos[x2] {
    			pos[x2] = true
    			xs = append(xs, x2)
    		}
    		segs = append(segs, []int{y1, x1, x2, 1})
    		segs = append(segs, []int{y2, x1, x2, -1})
    	}
    	sort.Slice(segs, func(i, j int) bool { return segs[i][0] < segs[j][0] })
    	sort.Ints(xs)
    	tree := NewSegmentTree(xs)
    	d := make(map[int]int, len(xs))
    	for i, x := range xs {
    		d[x] = i
    	}
    	area := 0.0
    	y0 := 0
    	for _, s := range segs {
    		y, x1, x2, k := s[0], s[1], s[2], s[3]
    		area += float64(y-y0) * float64(tree.query())
    		tree.modify(1, d[x1], d[x2]-1, k)
    		y0 = y
    	}
    	target := area / 2.0
    	area = 0.0
    	y0 = 0
    	for _, s := range segs {
    		y, x1, x2, k := s[0], s[1], s[2], s[3]
    		curLen := tree.query()
    		t := float64(y-y0) * float64(curLen)
    		if area+t >= target {
    			return float64(y0) + (target-area)/float64(curLen)
    		}
    		area += t
    		tree.modify(1, d[x1], d[x2]-1, k)
    		y0 = y
    	}
    	return 0.0
    }
    
    
  • class Node {
        l = 0;
        r = 0;
        cnt = 0;
        length = 0;
    }
    
    class SegmentTree {
        private tr: Node[];
        private nums: number[];
        constructor(nums: number[]) {
            this.nums = nums;
            const n = nums.length - 1;
            this.tr = Array.from({ length: n << 2 }, () => new Node());
            this.build(1, 0, n - 1);
        }
    
        private build(u: number, l: number, r: number): void {
            this.tr[u].l = l;
            this.tr[u].r = r;
            if (l !== r) {
                const mid = (l + r) >> 1;
                this.build(u << 1, l, mid);
                this.build((u << 1) | 1, mid + 1, r);
            }
        }
    
        modify(u: number, l: number, r: number, k: number): void {
            if (l > r) return;
            if (this.tr[u].l >= l && this.tr[u].r <= r) {
                this.tr[u].cnt += k;
            } else {
                const mid = (this.tr[u].l + this.tr[u].r) >> 1;
                if (l <= mid) this.modify(u << 1, l, r, k);
                if (r > mid) this.modify((u << 1) | 1, l, r, k);
            }
            this.pushup(u);
        }
    
        private pushup(u: number): void {
            if (this.tr[u].cnt > 0) {
                this.tr[u].length = this.nums[this.tr[u].r + 1] - this.nums[this.tr[u].l];
            } else if (this.tr[u].l === this.tr[u].r) {
                this.tr[u].length = 0;
            } else {
                this.tr[u].length = this.tr[u << 1].length + this.tr[(u << 1) | 1].length;
            }
        }
    
        query(): number {
            return this.tr[1].length;
        }
    }
    
    function separateSquares(squares: number[][]): number {
        const xsSet = new Set<number>();
        const segs: number[][] = [];
        for (const [x1, y1, l] of squares) {
            const [x2, y2] = [x1 + l, y1 + l];
            xsSet.add(x1);
            xsSet.add(x2);
            segs.push([y1, x1, x2, 1]);
            segs.push([y2, x1, x2, -1]);
        }
        segs.sort((a, b) => a[0] - b[0]);
        const xs = Array.from(xsSet);
        xs.sort((a, b) => a - b);
        const tree = new SegmentTree(xs);
        const d = new Map<number, number>();
        for (let i = 0; i < xs.length; i++) {
            d.set(xs[i], i);
        }
        let area = 0.0;
        let y0 = 0;
        for (const [y, x1, x2, k] of segs) {
            area += (y - y0) * tree.query();
            tree.modify(1, d.get(x1)!, d.get(x2)! - 1, k);
            y0 = y;
        }
        const target = area / 2.0;
        area = 0.0;
        y0 = 0;
        for (const [y, x1, x2, k] of segs) {
            const curLen = tree.query();
            const t = (y - y0) * curLen;
            if (area + t >= target) {
                return y0 + (target - area) / curLen;
            }
            area += t;
            tree.modify(1, d.get(x1)!, d.get(x2)! - 1, k);
            y0 = y;
        }
        return 0.0;
    }
    
    

All Problems

All Solutions