这道题首先要知道可以讲横纵坐标分开讨论。
这样就转化为区间贪心的问题。
要注意的是要用并查集优化一下。
对左端点排序,然后从右端点找到第一个没有被使用的点。
假设i点的根节点为x,并且x在区间内,就合并:pre[x] = find(x+1)。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e3+5;
int Case = 1;
int n, m;
struct node{
	int l, r, id;
	bool operator<(const node x)const{
		return r < x.r;
	}
}A[maxn], B[maxn];
int res[maxn][2];
int pre[maxn];
int find(int x) {
	int t = x;
	while(pre[t] != t) t = pre[t];
	while(t != x) {
		int c = pre[x];
		pre[x] = t;
		x = c;
	}
	return t;
}

void init() {
	for(int i = 1; i <= n+1; i++) pre[i] = i;
}

void solve() {
    for(int i = 1; i <= n; i++) {
    	int xl, yl, xr, yr;
    	scanf("%d%d%d%d", &xl, &yl, &xr, &yr);
    	A[i].l = xl;A[i].r = xr;A[i].id = i;
    	B[i].l = yl;B[i].r = yr;B[i].id = i;    	
    }
    init();
    sort(A+1, A+1+n);
    sort(B+1, B+1+n);
	for(int i = 1; i <= n; i++) {
		int x = find(A[i].l);
		if(x <= A[i].r) res[A[i].id][0] = x, pre[x] = find(x+1);
		else {
			printf("IMPOSSIBLE\n");
			return;
		}
	}
	init();
	for(int i = 1; i <= n; i++) {
		int x = find(B[i].l);
		if(x <= B[i].r) res[B[i].id][1] = x, pre[x] = find(x+1);
		else {
			printf("IMPOSSIBLE\n");
			return;
		}
	}
	for(int i = 1; i <= n; i++) {
		printf("%d %d\n", res[i][0], res[i][1]);
	}
    return;
}

int main() {
    while(scanf("%d", &n) == 1 && n) {
        solve();
    }
    return 0;
}