Wilbur is playing with a set of n points on the coordinate plane. All points have non-negative integer coordinates. Moreover, if some point (x, y) belongs to the set, then all points (x', y'), such that 0 ≤ x' ≤ x and 0 ≤ y' ≤ y also belong to this set.

Now Wilbur wants to number the points in the set he has, that is assign them distinct integer numbers from 1 to n. In order to make the numbering aesthetically pleasing, Wilbur imposes the condition that if some point (x, y) gets number i, then all (x',y') from the set, such that x' ≥ x and y' ≥ y must be assigned a number not less than i. For example, for a set of four points (0, 0), (0, 1), (1, 0) and (1, 1), there are two aesthetically pleasing numberings. One is 1, 2, 3, 4 and another one is 1, 3, 2, 4.

Wilbur's friend comes along and challenges Wilbur. For any point he defines it's special value as s(x, y) = y - x. Now he gives Wilbur some w_1, w_2,..., w_{n}, and asks him to find an aesthetically pleasing numbering of the points in the set, such that the point that gets number i has it's special value equal to w_{i}, that is s(x_{i}, y_{i}) = y_{i} - x_{i} = w_{i}.

Now Wilbur asks you to help him with this challenge.


-----Input-----

The first line of the input consists of a single integer n (1 ≤ n ≤ 100 000) — the number of points in the set Wilbur is playing with.

Next follow n lines with points descriptions. Each line contains two integers x and y (0 ≤ x, y ≤ 100 000), that give one point in Wilbur's set. It's guaranteed that all points are distinct. Also, it is guaranteed that if some point (x, y) is present in the input, then all points (x', y'), such that 0 ≤ x' ≤ x and 0 ≤ y' ≤ y, are also present in the input.

The last line of the input contains n integers. The i-th of them is w_{i} ( - 100 000 ≤ w_{i} ≤ 100 000) — the required special value of the point that gets number i in any aesthetically pleasing numbering.


-----Output-----

If there exists an aesthetically pleasant numbering of points in the set, such that s(x_{i}, y_{i}) = y_{i} - x_{i} = w_{i}, then print "YES" on the first line of the output. Otherwise, print "NO".

If a solution exists, proceed output with n lines. On the i-th of these lines print the point of the set that gets number i. If there are multiple solutions, print any of them.


-----Examples-----
Input
5
2 0
0 0
1 0
1 1
0 1
0 -1 -2 1 0

Output
YES
0 0
1 0
2 0
0 1
1 1

Input
3
1 0
0 0
2 0
0 1 2

Output
NO



-----Note-----

In the first sample, point (2, 0) gets number 3, point (0, 0) gets number one, point (1, 0) gets number 2, point (1, 1) gets number 5 and point (0, 1) gets number 4. One can easily check that this numbering is aesthetically pleasing and y_{i} - x_{i} = w_{i}.

In the second sample, the special values of the points in the set are 0,  - 1, and  - 2 while the sequence that the friend gives to Wilbur is 0, 1, 2. Therefore, the answer does not exist.

Difficulty: MEDIUM_HARD
Tags: Sorting

Combinatorics

Greedy algorithms
Skill types: Sorting

Greedy algorithms

Starter code:

Solutions:
from sys import stdin
_data = iter(stdin.read().split('\n'))
input = lambda : next(_data)
n = int(input())
(ref, front) = ({}, {})
ans = []
(max_x, max_y) = (0, 0)
for _ in range(n):
	(x, y) = list(map(int, input().split()))
	max_x = max(max_x, x)
	max_y = max(max_y, y)
	ref[x, y] = 2
	if x == 0:
		ref[x, y] -= 1
	if y == 0:
		ref[x, y] -= 1
	if (x, y) == (0, 0):
		del ref[x, y]
		front[y - x] = (x, y)
ws = list(map(int, input().split()))
for w in ws:
	if w not in front:
		ans = []
		break
	(x, y) = front.pop(w)
	ans.append((x, y))
	for (dx, dy) in ((1, 0), (0, 1)):
		(nx, ny) = (x + dx, y + dy)
		if (nx, ny) not in ref:
			continue
		ref[nx, ny] -= 1
		if ref[nx, ny] == 0:
			del ref[nx, ny]
			front[ny - nx] = (nx, ny)
if ans:
	print('YES')
	print('\n'.join(('{} {}'.format(x, y) for (x, y) in ans)))
else:
	print('NO')


n = int(input())
opens = {}
sums = [n - i for i in range(n)] + [0] * (n + 1)
for i in range(n):
	t = tuple(map(int, input().split()))
	opens[t] = 1
nums = list(map(int, input().split()))
res = 1
res_nums = []
for elem in nums:
	f = 1
	x = 0
	try:
		x = sums[elem + n]
	except:
		f = 0
	y = x + elem
	try:
		u = opens[x, y]
	except KeyError:
		f = 0
	try:
		if opens[x, y - 1] == 1:
			f = 0
	except KeyError:
		pass
	try:
		if opens[x - 1, y] == 1:
			f = 0
	except KeyError:
		pass
	if f == 0:
		res = 0
		break
	sums[elem + n] += 1
	opens[x, y] = 0
	res_nums.append((x, y))
print('YES' if res else 'NO')
if res:
	for elem in res_nums:
		print(str(elem[0]) + ' ' + str(elem[1]))


from collections import namedtuple, defaultdict, Counter
Point = namedtuple('Point', 'x y')
n = int(input())
pts = [Point(*list(map(int, input().split()))) for _ in range(n)]
have = Counter()
for pt in pts:
	have[pt.y - pt.x] += 1
ws = list(map(int, input().split()))
buckets = defaultdict(list)
for (i, w) in enumerate(ws):
	if have[w] == 0 or (w == 0 and (len(buckets[1]) != len(buckets[0]) or len(buckets[-1]) != len(buckets[0])) or (w > 0 and (len(buckets[w + 1]) != len(buckets[w]) or len(buckets[w - 1]) != len(buckets[w]) + 1)) or (w < 0 and (len(buckets[w - 1]) != len(buckets[w]) or len(buckets[w + 1]) != len(buckets[w]) + 1))):
		print('NO')
		return
	buckets[w].append(i)
	have[w] -= 1
ans = []
for (w, bucket) in list(buckets.items()):
	for (x, i) in enumerate(bucket, max(0, -w)):
		ans.append((Point(x, w + x), i))
ans.sort(key=lambda item: item[1])
print('YES')
print('\n'.join(('%d %d' % pt for (pt, i) in ans)))


from bisect import bisect_left
from functools import cmp_to_key

def mp():
	return map(int, input().split())

def lt():
	return list(map(int, input().split()))

def pt(x):
	print(x)

def ip():
	return input()

def it():
	return int(input())

def sl(x):
	return [t for t in x]

def spl(x):
	return x.split()

def aj(liste, item):
	liste.append(item)

def bin(x):
	return '{0:b}'.format(x)
n = it()
visited = {}
E = {}
for i in range(n):
	(a, b) = mp()
	visited[a, b] = False
	if b - a in E:
		r = bisect_left(E[b - a], [a, b])
		if r == len(E[b - a]):
			E[b - a].append([a, b])
		else:
			E[b - a].insert(r, [a, b])
	else:
		E[b - a] = [[a, b]]
L = lt()[::-1]
res = []
for i in L:
	if not i in E or E[i] == []:
		bool = False
		break
	else:
		r = E[i].pop()
		(x, y) = (r[0], r[1])
		if (not (x + 1, y) in visited or visited[x + 1, y]) and (not (x, y + 1) in visited or visited[x, y + 1]):
			visited[x, y] = True
			res.append([x, y])
		else:
			bool = False
			break
res = res[::-1]
if bool:
	print('YES')
	for i in res:
		print(' '.join([str(x) for x in i]))
else:
	print('NO')


n = int(input())
R = lambda : list(map(int, input().split()))
p = []
w = {}
r = {}
pr = {}
from collections import deque
for _ in range(n):
	(x, y) = R()
	p.append((x, y))
p = sorted(p)
for (i, wi) in enumerate(list(R()), 1):
	if wi not in w:
		w[wi] = deque()
	w[wi].append(i)

def solve(p, w, r):
	for i in range(len(p)):
		d = p[i][1] - p[i][0]
		if d in w:
			q = w[d]
			if len(q) > 0:
				ind = q.popleft()
				r[ind] = p[i]
				pr[p[i]] = ind
				if not check_neighbours(p[i], ind, pr):
					return 0
			else:
				return 0
		else:
			return 0
	return 1

def check_neighbours(p, ind, pr):
	n1 = (p[0] - 1, p[1])
	n2 = (p[0], p[1] - 1)
	n3 = (p[0] - 1, p[1] - 1)
	return check_neighbour(n1, ind, pr) and check_neighbour(n2, ind, pr) and check_neighbour(n3, ind, pr)

def check_neighbour(nb, ind, pr):
	if nb in pr:
		if pr[nb] > ind:
			return 0
	return 1
if solve(p, w, r) == 0:
	print('NO')
else:
	print('YES')
	for (k, v) in sorted(r.items()):
		print(v[0], v[1])


from collections import deque
dp = {}
for i in range(int(input())):
	(x, y) = list(map(int, input().split()))
	if y - x in dp:
		dp[y - x].append((x, y))
	else:
		dp[y - x] = [(x, y)]
for i in dp:
	dp[i].sort()
	dp[i] = deque(dp[i])
w = list(map(int, input().split()))
ans = [0] * len(w)
flag = 1
for i in range(len(w)):
	if not w[i] in dp or not len(dp[w[i]]):
		flag = 0
		break
	ans[i] = dp[w[i]].popleft()
if not flag:
	print('NO')
else:
	for i in range(1, len(ans)):
		if ans[i][0] <= ans[i - 1][0] and ans[i][1] <= ans[i - 1][1]:
			flag = 0
	if not flag:
		print('NO')
	else:
		print('YES')
		for i in ans:
			print(i[0], i[1])


from collections import deque

def ordering(s, ws):
	pbs = {}
	for p in sorted(s):
		pbs.setdefault(p[1] - p[0], deque()).append(p)
	o = []
	os = set()
	for w in ws:
		try:
			p = pbs[w].popleft()
		except (IndexError, KeyError):
			return None
		if p[0] > 0 and (p[0] - 1, p[1]) not in os or (p[1] > 0 and (p[0], p[1] - 1) not in os):
			return None
		o.append(p)
		os.add(p)
	return o

def pair(x, y):
	return (x, y)
n = int(input())
s = {pair(*map(int, input().split())) for _ in range(n)}
ws = tuple(map(int, input().split()))
o = ordering(s, ws)
if o:
	print('YES')
	for p in o:
		print('{} {}'.format(*p))
else:
	print('NO')


def binsearch(lofpoints, l, r, w, arr):
	if l > r:
		return 'None'
	mid = (l + r) // 2
	if lofpoints[mid][0] == w and arr[mid] == 1:
		if mid == 0:
			arr[mid] = 0
			return mid
		elif lofpoints[mid - 1][0] != w or arr[mid - 1] == 0:
			arr[mid] = 0
			return mid
		else:
			return binsearch(lofpoints, l, mid - 1, w, arr)
	if lofpoints[mid][0] == w and arr[mid] == 0:
		return binsearch(lofpoints, mid + 1, r, w, arr)
	if lofpoints[mid][0] < w:
		return binsearch(lofpoints, mid + 1, r, w, arr)
	if lofpoints[mid][0] > w:
		return binsearch(lofpoints, l, mid - 1, w, arr)
n = int(input())
lofpoints = []
for i in range(n):
	l = input().split()
	x = int(l[0])
	y = int(l[1])
	lofpoints.append((y - x, x, y))
lofpoints.sort()
w = input().split()
wi = [int(i) for i in w]
arr = [1 for i in range(n)]
lsol = []
done = 1
for i in range(n):
	x = binsearch(lofpoints, 0, n - 1, wi[i], arr)
	if x == 'None':
		done = 0
		break
	elif lsol == []:
		lsol.append((lofpoints[x][1], lofpoints[x][2]))
	elif lofpoints[x][1] < lsol[-1][0] and lofpoints[x][2] < lsol[-1][1]:
		done = 0
		break
	else:
		lsol.append((lofpoints[x][1], lofpoints[x][2]))
if done == 1:
	hashi = dict()
	for i in range(n):
		hashi[lsol[i][0], lsol[i][1]] = i
	for i in hashi:
		x = i[0]
		y = i[1]
		t = hashi[i]
		if (x, y + 1) in hashi:
			if hashi[x, y + 1] < t:
				done = 0
				break
		if (x + 1, y) in hashi:
			if hashi[x + 1, y] < t:
				done = 0
				break
	if done == 0:
		print('NO')
	else:
		print('YES')
		for i in lsol:
			print(i[0], i[1])
else:
	print('NO')


def __starting_point():
	n = int(input())
	maxX = [-1] * 100005
	for _ in range(n):
		(px, py) = [int(x) for x in input().split()]
		maxX[py] = max(maxX[py], px)
	w = [int(x) for x in input().split()]
	p = [-1] * 100005
	p[0] = 0
	wdict = dict()
	wdict[0] = (0, 0)
	res = []
	for wi in w:
		if wi in wdict:
			(px, py) = wdict.pop(wi)
			res.append((px, py))
			if maxX[py] > px:
				wdict[py - (px + 1)] = (px + 1, py)
				p[py] += 1
			if maxX[py + 1] != -1 and p[py + 1] == -1:
				wdict[py + 1] = (0, py + 1)
				p[py + 1] += 1
		else:
			break
	if len(res) == n:
		print('YES')
		for ares in res:
			print(ares[0], ares[1])
	else:
		print('NO')
__starting_point()


from collections import defaultdict

def solve():
	N = int(input())
	maxx = 0
	maxy = 0
	WS = defaultdict(list)
	for i in range(N):
		(x, y) = map(int, input().split())
		WS[y - x].append((x, y))
		maxx = max(maxx, x)
		maxy = max(maxy, y)
	for w in WS:
		WS[w].sort(reverse=True)
	W = list(map(int, input().split()))
	ans = [None] * N
	mx = [0] * (maxy + 1)
	my = [0] * (maxx + 1)
	for i in range(N):
		w = W[i]
		if WS[w]:
			ans[i] = (ax, ay) = WS[w].pop()
			if mx[ay] == ax and my[ax] == ay:
				mx[ay] = ax + 1
				my[ax] = ay + 1
			else:
				print('NO')
				return
		else:
			print('NO')
			return
	print('YES')
	for a in ans:
		print(a[0], a[1])
solve()


n = int(input().rstrip())
l = set()
for i in range(n):
	l.add(tuple(map(int, input().rstrip().split())))
w = list(map(int, input().rstrip().split()))
d = {0: (0, 0)}
s = ''
visited = set()
visited.add((0, 0))
for k in w:
	if d.get(k, None) is None:
		print('NO')
		exit(0)
	p = d[k]
	del d[k]
	s += '{} {}\n'.format(*p)
	if p[1] == 0 and (p[0] + 1, p[1]) in l:
		visited.add((p[0] + 1, p[1]))
		d[-p[0] - 1] = (p[0] + 1, 0)
	elif (p[0] + 1, p[1] - 1) in visited and (p[0] + 1, p[1]) in l:
		visited.add((p[0] + 1, p[1]))
		d[p[1] - p[0] - 1] = (p[0] + 1, p[1])
	if p[0] == 0 and (0, p[1] + 1) in l:
		d[p[1] + 1] = (0, p[1] + 1)
		visited.add((0, p[1] + 1))
	elif (p[0] - 1, p[1] + 1) in visited and (p[0], p[1] + 1) in l:
		visited.add((p[0], p[1] + 1))
		d[p[1] - p[0] + 1] = (p[0], p[1] + 1)
print('YES')
print(s, end='')


from collections import defaultdict
from operator import itemgetter
n = int(input())
points = []
point_weights = defaultdict(list)
for _ in range(n):
	(x, y) = tuple(map(int, input().split()))
	points.append((x, y))
	point_weights[y - x].append((x, y))
weights = list(map(int, input().split()))
points.sort(key=itemgetter(0, 1))
for (w, p) in point_weights.items():
	point_weights[w] = sorted(p, key=itemgetter(0, 1), reverse=True)
ans = 'YES'
ans_arr = []
for weight in weights:
	if weight not in point_weights:
		ans = 'NO'
		break
	elif len(point_weights[weight]) == 0:
		ans = 'NO'
		break
	else:
		ans_arr.append(point_weights[weight].pop())
for i in range(1, len(ans_arr)):
	if ans_arr[i][0] <= ans_arr[i - 1][0] and ans_arr[i][1] <= ans_arr[i - 1][1]:
		ans = 'NO'
		break
print(ans)
if ans == 'YES':
	for point in ans_arr:
		print(*point)


import collections
lis = []
n = int(input())
dic = collections.defaultdict(list)
for i in range(n):
	lis.append(tuple(map(int, input().split())))
lis.sort(reverse=True)
for i in range(n):
	dic[lis[i][1] - lis[i][0]].append(lis[i])
lis1 = list(map(int, input().split()))
st = ''
mx1 = (-1, -1)
mx2 = (-1, -1)
for i in lis1:
	if dic[i]:
		a = dic[i].pop()
		if a >= mx1 or a >= mx2:
			if mx1[0] < a[0]:
				mx1 = a
			if mx2[1] < a[1]:
				mx2 = a
			st += str(a[0]) + ' ' + str(a[1]) + '\n'
		else:
			print('NO')
			return
	else:
		print('NO')
		return
print('YES')
print(st, end='')


from itertools import combinations, permutations
from collections import defaultdict

def zeror():
	return 0

def solution(n, c, cw, w):
	c.sort(key=lambda tup: tup[0])
	for (k, v) in cw.items():
		cw[k] = sorted(v, key=lambda tup: tup[0])[::-1]
	ans = []
	for elem in w:
		if elem not in cw:
			print('NO')
			return
		else:
			ans.append(cw[elem].pop())
	temp = ans[0]
	for elem in ans[1:]:
		if temp[0] >= elem[0] and temp[1] >= elem[1]:
			print('NO')
			return
		temp = elem
	print('YES')
	for elem in ans:
		print(elem[0], elem[1])

def main():
	n = int(input())
	coordinates = []
	coor_weights = defaultdict(list)
	for _ in range(n):
		coordinates.append(tuple(map(int, input().strip().split())))
		coor_weights[coordinates[-1][1] - coordinates[-1][0]].append((coordinates[-1][0], coordinates[-1][1]))
	weigths = list(map(int, input().strip().split()))
	solution(n, coordinates, coor_weights, weigths)

def __starting_point():
	main()
__starting_point()


def main():
	n = int(input())
	diag = [0] * 200005
	use = [0] * 200005
	for i in range(n):
		(x, y) = [int(i) for i in input().split(' ')]
		c = y - x
		if c > 0:
			diag[c] = max(x + 1, diag[c])
		else:
			diag[c] = max(y + 1, diag[c])
	table = set()
	for i in range(100005):
		table.add((-1, i))
		table.add((i, -1))
	result = []
	for v in [int(i) for i in input().split(' ')]:
		if v > 0:
			x = use[v]
			y = x + v
		else:
			y = use[v]
			x = y - v
		use[v] += 1
		if use[v] > diag[v]:
			print('NO')
			return
		if (x - 1, y) not in table or (x, y - 1) not in table:
			print('NO')
			return
		table.add((x, y))
		result.append((x, y))
	print('YES')
	for v in result:
		print(v[0], v[1])
main()


__author__ = 'mac'
from collections import Counter

def sortByDiag(elem):
	return elem[0] * elem[0] + elem[1] * elem[1]
count = int(input())
points = {}
compList = []
for i in range(count):
	(x, y) = [int(x) for x in input().strip().split(' ')]
	w = y - x
	compList.append(w)
	if not w in points:
		points[w] = []
	points[w].append([x, y])
wArr = []
for x in input().strip().split(' '):
	if len(wArr) > 1 and int(x) == wArr[-1] or abs(int(x)) > len(wArr):
		print('NO')
		exit()
	wArr.append(int(x))
c1 = Counter(wArr)
c2 = Counter(compList)
diff = c1 - c2
if len(list(diff.elements())) != 0:
	print('NO')
	exit()
print('YES')
for e in points:
	points[e] = sorted(points[e], key=sortByDiag)
for i in wArr:
	temp = points[i].pop(0)
	print(temp[0], temp[1])


from operator import itemgetter
from collections import defaultdict
n = int(input())
coor = []
coor_list = defaultdict(list)
for _ in range(n):
	(x, y) = list(map(int, input().split()))
	coor.append((x, y))
	coor_list[y - x].append((x, y))
coor.sort(key=itemgetter(0, 1))
order = {cor: i for (i, cor) in enumerate(coor)}
for (x, y) in coor_list.items():
	coor_list[x] = sorted(y, key=itemgetter(0, 1), reverse=True)
nums = list(map(int, input().split()))
result = []
for i in nums:
	if i not in coor_list:
		print('NO')
		return
	else:
		result.append(coor_list[i].pop())
for i in range(1, n):
	if result[i][0] <= result[i - 1][0] and result[i][1] <= result[i - 1][1]:
		print('NO')
		return
print('YES')
for i in result:
	print(*i)


n = int(input())
p = sorted([tuple(map(int, input().split())) for _ in range(n)])
arr = list(map(int, input().split()))
(w, r, pr) = ({}, {}, {})
for (i, wi) in enumerate(arr, 1):
	if wi not in w:
		w[wi] = []
	w[wi].append(i)

def is_nbr(nb, i):
	return 0 if pr.get(nb, 0) > i else 1

def check_nbrs(p, i):
	n1 = (p[0] - 1, p[1])
	n2 = (p[0], p[1] - 1)
	n3 = (p[0] - 1, p[1] - 1)
	return is_nbr(n1, i) and is_nbr(n2, i) and is_nbr(n3, i)

def solve():
	for i in range(len(p)):
		d = p[i][1] - p[i][0]
		if d not in w:
			return 0
		q = w[d]
		if not q:
			return 0
		ind = q.pop(0)
		r[ind] = p[i]
		pr[p[i]] = ind
		if not check_nbrs(p[i], ind):
			return 0
	return 1
if solve() == 0:
	print('NO')
else:
	print('YES')
	for (k, v) in sorted(r.items()):
		print(v[0], v[1])


from bisect import bisect_left
n = int(input())
mas = []
for i in range(n):
	mas.append(0)
for i in range(n):
	(x, y) = list(map(int, input().split()))
	mas[x] = max(mas[x], y)
w = list(map(int, input().split()))
for i in range(n):
	w[i] = -w[i]
s = []
r = []
res1 = []
res2 = []
res3 = []
for i in range(n):
	s.append(i)
	r.append(i)
	res2.append(-1)
	s[i] -= mas[i] + 1
error = 0
for i in range(n):
	if error == 1:
		break
	t = bisect_left(r, w[i])
	if t >= n or r[t] != w[i]:
		error = 1
		break
	else:
		r[t] = r[t] - 1
		if r[t] < s[t] or (t > 0 and r[t] == r[t - 1]):
			error = 1
			break
	res1.append(t)
	res2[t] = res2[t] + 1
	res3.append(res2[t])
if error == 1:
	print('NO')
else:
	print('YES')
	for i in range(n):
		print(str(res1[i]) + ' ' + str(res3[i]))


n = int(input())
MAX = 100000
coord = [list() for i in range(2 * MAX + 1)]
for i in range(n):
	(x, y) = map(int, input().split())
	coord[y - x - MAX].append((x, y))
w = list(map(int, input().split()))
for i in range(2 * MAX + 1):
	coord[i].sort()
ans = [(0, 0) for i in range(n)]
possible = True
last_x = [-1] * (MAX + 1)
last_y = [-1] * (MAX + 1)
for i in range(n):
	if len(coord[w[i] - MAX]) > 0:
		x = coord[w[i] - MAX][0][0]
		y = coord[w[i] - MAX][0][1]
		if last_x[y] == x - 1 and last_y[x] == y - 1:
			last_x[y] += 1
			last_y[x] += 1
			ans[i] = (x, y)
			coord[w[i] - MAX].pop(0)
		else:
			possible = False
			break
	else:
		possible = False
		break
if possible:
	print('YES')
	print('\n'.join([' '.join(map(str, coords)) for coords in ans]))
else:
	print('NO')


n = int(input())
max_y = {}
for i in range(n):
	(x, y) = map(int, input().split())
	key = y - x
	if key not in max_y or y > max_y[key]:
		max_y[key] = y
curr_y = {key: max(key, 0) for key in max_y}
result = []

def fail():
	print('NO')
	import sys
	sys.exit()
for key in map(int, input().split()):
	if key not in curr_y:
		fail()
	y = curr_y[key]
	if y > max_y[key]:
		fail()
	if key + 1 in curr_y and curr_y[key + 1] != y + 1:
		fail()
	if key - 1 in curr_y and curr_y[key - 1] != y:
		fail()
	result.append('%d %d' % (y - key, y))
	curr_y[key] = y + 1
print('YES')
print('\n'.join(result))


import collections
import heapq

class SegmentTree(object):

	def __init__(self, size):
		self.capacity = 1 << len(bin(size - 1)) - 2
		self.tree = [-1] * self.capacity * 2
		self.tree[0] = size
		self.left = set()
		p = self.capacity
		while p:
			self.left.add(p)
			p >>= 1

	def update(self, x, y):
		pos = self.capacity + x
		while pos:
			if y > self.tree[pos]:
				self.tree[pos] = y
			pos >>= 1

	def getmax(self, x):
		pos = self.capacity + x
		y = self.tree[pos]
		while pos:
			if y < self.tree[pos]:
				y = self.tree[pos]
			if pos & 1:
				pos = (pos >> 1) + 1
				if pos in self.left:
					break
			else:
				pos >>= 1
		return y

def read_data():
	n = int(input())
	sxy = collections.defaultdict(list)
	for i in range(n):
		(x, y) = map(int, input().split())
		heapq.heappush(sxy[y - x], x)
	ws = list(map(int, input().split()))
	return (n, sxy, ws)

def solve(n, sxy, ws):
	path = []
	for w in ws:
		sxyw = sxy[w]
		if sxyw:
			x = heapq.heappop(sxy[w])
			y = w + x
			path.append((x, y))
		else:
			return False
	if is_valid(path):
		return path
	else:
		return False

def is_valid(path):
	xys = compress(path)
	segtree = SegmentTree(len(xys))
	for (x, y) in xys:
		maxy = segtree.getmax(x)
		if maxy >= y:
			return False
		segtree.update(x, y)
	return True

def compress(path):
	xset = set()
	for (x, y) in path:
		xset.add(x)
	xuniq = list(xset)
	xuniq.sort()
	dic = {x: i for (i, x) in enumerate(xuniq)}
	xys = [(dic[x], y) for (x, y) in path]
	return xys
(n, sxy, ws) = read_data()
result = solve(n, sxy, ws)
if result:
	print('YES')
	for (x, y) in result:
		print(x, y)
else:
	print('NO')


read = lambda : map(int, input().split())
n = int(input())
Max = {}
for i in range(n):
	(x, y) = read()
	s = y - x
	if s not in Max or y > Max[s]:
		Max[s] = y
cur = {i: max(i, 0) for i in Max}
ans = []

def no():
	print('NO')
	exit()
for i in read():
	if i not in cur:
		no()
	y = cur[i]
	f2 = y > Max[i]
	f3 = i + 1 in cur and cur[i + 1] != y + 1
	f4 = i - 1 in cur and cur[i - 1] != y
	if f2 or f3 or f4:
		no()
	ans.append('%d %d' % (y - i, y))
	cur[i] = y + 1
print('YES\n' + '\n'.join(ans))