[AtCoder] E - Packing Under Range Regulations
Key idea: For a given box and a list of balls that can be placed in this box, we should choose the ball with the smallest R.
Proof: say we have box B and ball X and Y with R[X] < R[Y]. If we put ball Y in B, then ball X must be put in another box C, with C > B. There will be 2 cases to consider:
1. R[X] <= C: we can simply swap the position of ball X and Y, without impacting the final answer.
2. R[X] > C: we can not put ball X to box C, this will turn the answer from yes to no.
Solution:
1. sort all [L, R] in increasing L order.
2. start from the 1st box, iterate [L, R] ranges from left to right, as long as a ball can be placed in the current box, add the ball's right bound R to a min heap H.
optimization: there are up to 10^9 boxes, so incrementing the current box number by 1 at a time is too slow. There are only up to 2 * 10^5 balls, so most of the 10^9 boxes will be unoccupied.
To speed up this simulation process, we check if the min heap H is empty before we try to add balls' right bound R to H.
If H is empty, it means no balls can be placed to any of the boxes in [current box, current unprocessed box's L - 1], we can simply set the current box number to be current unprocessed box's L.
3. pick the ball with the smallest R from the min heap and try to put it in the current box. If impossible, the answer is No. Otherwise move to the next box.
static void solve(int testCnt) {
for (int testNumber = 0; testNumber < testCnt; testNumber++) {
int n = in.nextInt();
int[][] a = new int[n][];
for(int i = 0; i < n; i++) {
a[i] = in.nextIntArrayPrimitive(2);
}
Arrays.sort(a, (e1, e2) -> {
if(e1[0] != e2[0]) {
return e1[0] - e2[0];
}
return e1[1] - e2[1];
});
//process all ranges from left to right and keep the current box number
//if the current box number == the current left bound of a range, add the current ball's right bound to a min heap
boolean ans = true;
int currBoxNum = 1;
PriorityQueue<Integer> rightBoundOfBallsToBePlaced = new PriorityQueue<>();
int i = 0;
while(i < n) {
if(rightBoundOfBallsToBePlaced.size() == 0) {
currBoxNum = a[i][0];
}
while(i < n && a[i][0] == currBoxNum) {
rightBoundOfBallsToBePlaced.add(a[i][1]);
i++;
}
if(rightBoundOfBallsToBePlaced.size() > 0) {
if(rightBoundOfBallsToBePlaced.peek() < currBoxNum) {
ans = false;
break;
}
rightBoundOfBallsToBePlaced.poll();
currBoxNum++;
}
}
while(rightBoundOfBallsToBePlaced.size() > 0 && rightBoundOfBallsToBePlaced.peek() >= currBoxNum) {
rightBoundOfBallsToBePlaced.poll();
currBoxNum++;
}
ans &= rightBoundOfBallsToBePlaced.size() == 0;
out.println(ans ? "Yes" : "No");
}
out.close();
}