Evlampiy was gifted a rooted tree. The vertices of the tree are numbered from $1$ to $n$. Each of its vertices also has an integer $a_i$ written on it. For each vertex $i$, Evlampiy calculated $c_i$ — the number of vertices $j$ in the subtree of vertex $i$, such that $a_j < a_i$. [Image]Illustration for the second example, the first integer is $a_i$ and the integer in parentheses is $c_i$

After the new year, Evlampiy could not remember what his gift was! He remembers the tree and the values of $c_i$, but he completely forgot which integers $a_i$ were written on the vertices.

Help him to restore initial integers!


-----Input-----

The first line contains an integer $n$ $(1 \leq n \leq 2000)$ — the number of vertices in the tree.

The next $n$ lines contain descriptions of vertices: the $i$-th line contains two integers $p_i$ and $c_i$ ($0 \leq p_i \leq n$; $0 \leq c_i \leq n-1$), where $p_i$ is the parent of vertex $i$ or $0$ if vertex $i$ is root, and $c_i$ is the number of vertices $j$ in the subtree of vertex $i$, such that $a_j < a_i$.

It is guaranteed that the values of $p_i$ describe a rooted tree with $n$ vertices.


-----Output-----

If a solution exists, in the first line print "YES", and in the second line output $n$ integers $a_i$ $(1 \leq a_i \leq {10}^{9})$. If there are several solutions, output any of them. One can prove that if there is a solution, then there is also a solution in which all $a_i$ are between $1$ and $10^9$.

If there are no solutions, print "NO".


-----Examples-----
Input
3
2 0
0 2
2 0

Output
YES
1 2 1 
Input
5
0 1
1 3
2 1
3 0
2 0

Output
YES
2 3 2 1 2

Difficulty: MEDIUM_HARD
Tags: Graph algorithms

Graph traversal

Constructive algorithms

Greedy algorithms

Tree algorithms

Data structures
Skill types: Data structures

Greedy algorithms

Starter code:

Solutions:
from sys import setrecursionlimit
setrecursionlimit(1000000)
n = int(input())
graph = [[] for _ in range(n + 1)]
ci = [0]

def solve(x):
	rst = []
	for s in graph[x]:
		rst.extend(solve(s))
	if len(rst) < ci[x]:
		raise ValueError
	rst.insert(ci[x], x)
	return rst
for i in range(1, n + 1):
	(p, c) = map(int, input().split())
	graph[p].append(i)
	ci.append(c)
try:
	ans = solve(graph[0][0])
except ValueError:
	print('NO')
else:
	print('YES')
	for i in range(1, n + 1):
		print(ans.index(i) + 1, end=' ')


import sys
readline = sys.stdin.readline

def parorder(Edge, p):
	N = len(Edge)
	par = [0] * N
	par[p] = -1
	stack = [p]
	order = []
	visited = set([p])
	ast = stack.append
	apo = order.append
	while stack:
		vn = stack.pop()
		apo(vn)
		for vf in Edge[vn]:
			if vf in visited:
				continue
			visited.add(vf)
			par[vf] = vn
			ast(vf)
	return (par, order)

def getcld(p):
	res = [[] for _ in range(len(p))]
	for (i, v) in enumerate(p[1:], 1):
		res[v].append(i)
	return res
N = int(readline())
root = None
Edge = [[] for _ in range(N)]
Cr = [None] * N
for a in range(N):
	(b, c) = map(int, readline().split())
	b -= 1
	if b == -1:
		root = a
	else:
		Edge[a].append(b)
		Edge[b].append(a)
	Cr[a] = c
(P, L) = parorder(Edge, root)
dp = [0] * N
for l in L[:0:-1]:
	p = P[l]
	dp[p] += 1 + dp[l]
if any((d < c for (d, c) in zip(dp, Cr))):
	print('NO')
else:
	print('YES')
	A = [None] * N
	dp2 = [[] for _ in range(N)]
	for l in L[:0:-1]:
		p = P[l]
		dp2[l] = dp2[l][:Cr[l]] + [l] + dp2[l][Cr[l]:]
		dp2[p].extend(dp2[l])
	dp2[root] = dp2[root][:Cr[root]] + [root] + dp2[root][Cr[root]:]
	Ans = [None] * N
	for i in range(N):
		Ans[dp2[root][i]] = i + 1
	print(' '.join(map(str, Ans)))


import sys
reader = (line.rstrip() for line in sys.stdin)
input = reader.__next__
n = int(input())
cs = [0] * (n + 1)
ps = [0] * (n + 1)
children = [[] for _ in range(n + 1)]
for i in range(1, n + 1):
	(p, c) = map(int, input().split())
	ps[i] = p
	children[p].append(i)
	cs[i] = c

def sortDescendants(v):
	result = []
	pos = cs[v]
	for child in children[v]:
		result += sortDescendants(child)
	if len(result) < pos:
		print('NO')
		sys.exit()
	result.insert(pos, v)
	return result
root = children[0][0]
order = sortDescendants(root)
a = [0] * n
for (i, v) in enumerate(order):
	a[v - 1] = i + 1
print('YES')
print(*a)


N = 2010
idx = 0
n = 0
root = 0
p = 0
head = [-1] * N
sz = [0] * N
vis = [0] * N
c = [0] * N
num = [0] * N

class node(object):

	def __init__(self):
		self.to = 0
		self.next = 0
edge = [node() for i in range(1, N + 1)]

def add(u, v):
	global idx, head, edge
	edge[idx].to = v
	edge[idx].next = head[u]
	head[u] = idx
	idx += 1

def dfs_in(x):
	global sz, head, edge
	sz[x] = 1
	i = head[x]
	while i != -1:
		y = edge[i].to
		dfs_in(y)
		sz[x] += sz[y]
		i = edge[i].next

def dfs(x):
	global head, vis, num, c, edge, n
	cnt = 0
	for i in range(1, n + 1):
		if vis[i] == 0:
			cnt += 1
		if c[x] + 1 == cnt:
			num[x] = i
			vis[i] = 1
			break
	i = head[x]
	while i != -1:
		y = edge[i].to
		dfs(y)
		i = edge[i].next
n = int(input())
for i in range(1, n + 1):
	(p, c[i]) = map(int, input().split())
	if p == 0:
		root = i
	else:
		add(p, i)
dfs_in(root)
for i in range(1, n + 1):
	if c[i] + 1 > sz[i]:
		print('NO')
		exit(0)
dfs(root)
print('YES')
for i in range(1, n + 1):
	print(num[i], end=' ')


n = int(input())
g = [[] for _ in range(n + 1)]
c = [0]
for i in range(1, n + 1):
	(p, ci) = map(int, input().split())
	g[p].append(i)
	c.append(ci)
b = True

def dfs(i):
	global b
	l = []
	for j in g[i]:
		l.extend(dfs(j))
	if c[i] > len(l):
		b = False
	l.insert(c[i], i)
	return l
l = dfs(g[0][0])
if b:
	ans = [0] * n
	for i in range(0, n):
		ans[l[i] - 1] = i + 1
	print('YES')
	print(*ans)
else:
	print('NO')


import sys

class SegmTree:

	def __init__(self, array=None, size=None):
		if array is not None:
			size = len(array)
		N = 1
		while N < size:
			N <<= 1
		self.N = N
		self.tree = [0] * (2 * self.N)
		if array is not None:
			for i in range(size):
				self.tree[i + self.N] = array[i]
			self.build()

	def build(self):
		for i in range(self.N - 1, 0, -1):
			self.tree[i] = self.tree[i << 1] + self.tree[i << 1 | 1]

	def add(self, i, value=1):
		i += self.N
		while i > 0:
			self.tree[i] += value
			i >>= 1

	def find_kth_nonzero(self, k):
		i = 1
		if k < 1 or k > self.tree[1]:
			return -1
		while i < self.N:
			i <<= 1
			if self.tree[i] < k:
				k -= self.tree[i]
				i |= 1
		return i - self.N
reader = (line.rstrip() for line in sys.stdin)
input = reader.__next__
n = int(input())
cs = [0] * n
ps = [0] * n
children = [[] for _ in range(n)]
for i in range(n):
	(p, c) = map(int, input().split())
	if p > 0:
		ps[i] = p - 1
		children[p - 1].append(i)
	else:
		root = i
	cs[i] = c
visited = [False] * n
stack = [root]
prev = -1
rank = [1] * n
while stack:
	v = stack.pop()
	if not visited[v]:
		visited[v] = True
		for to in children[v]:
			stack.append(v)
			stack.append(to)
	else:
		rank[v] += rank[prev]
	prev = v
unused = SegmTree([1] * n)
ans = [None] * n
stack = [root]
while stack:
	v = stack.pop()
	k = cs[v] + 1
	if k > rank[v]:
		print('NO')
		sys.exit()
	i = unused.find_kth_nonzero(k)
	ans[v] = i + 1
	unused.add(i, -1)
	stack.extend(children[v])
print('YES')
print(*ans)


from sys import stdin, stdout
valid = True

def getnumberfromtree(node, dic, slist):
	rst = []
	leftCnt = slist[node]
	global valid
	for next in dic[node]:
		subRst = getnumberfromtree(next, dic, slist)
		if subRst is None:
			return None
		rst.extend(subRst)
	if leftCnt > len(rst):
		valid = False
		return None
	rst.insert(leftCnt, node)
	return rst
n = int(stdin.readline())
dic = [[] for i in range(n)]
root = 0
slist = [0] * n
for i in range(n):
	pc = list(map(int, stdin.readline().split()))
	slist[i] = pc[1]
	if pc[0] == 0:
		root = i
	else:
		dic[pc[0] - 1].append(i)
res = getnumberfromtree(root, dic, slist)
if valid:
	stdout.write('YES' + '\n')
	for i in range(len(res)):
		stdout.write(str(res.index(i) + 1) + ' ')
else:
	stdout.write('NO')


import sys
sys.setrecursionlimit(2500)
from collections import defaultdict
children = defaultdict(set)
num_bigger = dict()
ans = dict()
n = int(input())
root = None
for me in range(1, n + 1):
	(parent, b) = input().split(' ')
	(parent, b) = (int(parent), int(b))
	num_bigger[me] = b
	if parent == 0:
		root = me
	else:
		children[parent].add(me)
assert root

def sorted_of(elem):
	ret = []
	for child in children[elem]:
		ret += sorted_of(child)
	if num_bigger[elem] <= len(ret):
		ret.insert(num_bigger[elem], elem)
	else:
		print('NO')
		sys.exit()
	return ret
s = sorted_of(root)
for i in range(n):
	ans[s[i]] = i + 1
print('YES')
print(' '.join((str(ans[i]) for i in range(1, n + 1))))


import os, sys
from io import BytesIO, IOBase

class SortedList:

	def __init__(self, iterable=None, _load=200):
		if iterable is None:
			iterable = []
		values = sorted(iterable)
		self._len = _len = len(values)
		self._load = _load
		self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
		self._list_lens = [len(_list) for _list in _lists]
		self._mins = [_list[0] for _list in _lists]
		self._fen_tree = []
		self._rebuild = True

	def _fen_build(self):
		self._fen_tree[:] = self._list_lens
		_fen_tree = self._fen_tree
		for i in range(len(_fen_tree)):
			if i | i + 1 < len(_fen_tree):
				_fen_tree[i | i + 1] += _fen_tree[i]
		self._rebuild = False

	def _fen_update(self, index, value):
		if not self._rebuild:
			_fen_tree = self._fen_tree
			while index < len(_fen_tree):
				_fen_tree[index] += value
				index |= index + 1

	def _fen_query(self, end):
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		x = 0
		while end:
			x += _fen_tree[end - 1]
			end &= end - 1
		return x

	def _fen_findkth(self, k):
		_list_lens = self._list_lens
		if k < _list_lens[0]:
			return (0, k)
		if k >= self._len - _list_lens[-1]:
			return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		idx = -1
		for d in reversed(range(len(_fen_tree).bit_length())):
			right_idx = idx + (1 << d)
			if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
				idx = right_idx
				k -= _fen_tree[idx]
		return (idx + 1, k)

	def _delete(self, pos, idx):
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len -= 1
		self._fen_update(pos, -1)
		del _lists[pos][idx]
		_list_lens[pos] -= 1
		if _list_lens[pos]:
			_mins[pos] = _lists[pos][0]
		else:
			del _lists[pos]
			del _list_lens[pos]
			del _mins[pos]
			self._rebuild = True

	def _loc_left(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(lo, pos) = (-1, len(_lists) - 1)
		while lo + 1 < pos:
			mi = lo + pos >> 1
			if value <= _mins[mi]:
				pos = mi
			else:
				lo = mi
		if pos and value <= _lists[pos - 1][-1]:
			pos -= 1
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value <= _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def _loc_right(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(pos, hi) = (0, len(_lists))
		while pos + 1 < hi:
			mi = pos + hi >> 1
			if value < _mins[mi]:
				hi = mi
			else:
				pos = mi
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value < _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def add(self, value):
		_load = self._load
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len += 1
		if _lists:
			(pos, idx) = self._loc_right(value)
			self._fen_update(pos, 1)
			_list = _lists[pos]
			_list.insert(idx, value)
			_list_lens[pos] += 1
			_mins[pos] = _list[0]
			if _load + _load < len(_list):
				_lists.insert(pos + 1, _list[_load:])
				_list_lens.insert(pos + 1, len(_list) - _load)
				_mins.insert(pos + 1, _list[_load])
				_list_lens[pos] = _load
				del _list[_load:]
				self._rebuild = True
		else:
			_lists.append([value])
			_mins.append(value)
			_list_lens.append(1)
			self._rebuild = True

	def discard(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_right(value)
			if idx and _lists[pos][idx - 1] == value:
				self._delete(pos, idx - 1)

	def remove(self, value):
		_len = self._len
		self.discard(value)
		if _len == self._len:
			raise ValueError('{0!r} not in list'.format(value))

	def pop(self, index=-1):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		value = self._lists[pos][idx]
		self._delete(pos, idx)
		return value

	def bisect_left(self, value):
		(pos, idx) = self._loc_left(value)
		return self._fen_query(pos) + idx

	def bisect_right(self, value):
		(pos, idx) = self._loc_right(value)
		return self._fen_query(pos) + idx

	def count(self, value):
		return self.bisect_right(value) - self.bisect_left(value)

	def __len__(self):
		return self._len

	def __getitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		return self._lists[pos][idx]

	def __delitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		self._delete(pos, idx)

	def __contains__(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_left(value)
			return idx < len(_lists[pos]) and _lists[pos][idx] == value
		return False

	def __iter__(self):
		return (value for _list in self._lists for value in _list)

	def __reversed__(self):
		return (value for _list in reversed(self._lists) for value in reversed(_list))

	def __repr__(self):
		return 'SortedList({0})'.format(list(self))

def dfs(root, path, ans, n):
	st = [root]
	nums = SortedList(range(1, n + 1))
	lst = [-1] * n
	cou = 0
	val = [-1] * n
	if ans[st[-1]] >= len(nums):
		print('NO')
		return
	val[st[-1] - 1] = nums[ans[st[-1]]]
	nums.discard(nums[ans[st[-1]]])
	lst[st[-1] - 1] = cou
	cou += 1
	while len(st):
		if not len(path[st[-1]]):
			(y, z) = (0, st[-1] - 1)
			for j in range(n):
				if lst[j] > lst[z] and val[j] < val[z]:
					y += 1
			if y != ans[z + 1]:
				print('NO')
				return
			st.pop()
			continue
		st.append(path[st[-1]].pop())
		if ans[st[-1]] >= len(nums):
			print('NO')
			return
		val[st[-1] - 1] = nums[ans[st[-1]]]
		nums.discard(nums[ans[st[-1]]])
		lst[st[-1] - 1] = cou
		cou += 1
	if val.count(-1):
		print('NO')
	else:
		print('YES')
		print(*val)

def main():
	n = int(input())
	path = [[] for _ in range(n + 1)]
	ans = [0] * (n + 1)
	for i in range(1, n + 1):
		(p, c) = map(int, input().split())
		if p:
			path[p].append(i)
		else:
			root = i
		ans[i] = c
	dfs(root, path, ans, n)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


from types import GeneratorType

def bootstrap(f, stack=[]):

	def wrappedfunc(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		else:
			to = f(*args, **kwargs)
			while True:
				if type(to) is GeneratorType:
					stack.append(to)
					to = next(to)
				else:
					stack.pop()
					if not stack:
						break
					to = stack[-1].send(to)
			return to
	return wrappedfunc

def main():
	n = int(input())
	p = [-1 for _ in range(n + 1)]
	c = [-1 for _ in range(n + 1)]
	children = [[] for _ in range(n + 1)]
	for i in range(1, n + 1):
		(pp, cc) = readIntArr()
		p[i] = pp
		c[i] = cc
		if pp == 0:
			root = i
		else:
			children[pp].append(i)

	@bootstrap
	def dfs(i):
		if len(children[i]) == 0:
			if c[i] > 0:
				possible[0] = False
			val = 1
			for zz in range(1, n + 1):
				if a[zz] >= val:
					a[zz] += 1
			a[i] = val
			yield [i]
		else:
			requiredCnts = c[i]
			childNodes = []
			for child in children[i]:
				for node in (yield dfs(child)):
					childNodes.append(node)
			if requiredCnts > len(childNodes):
				possible[0] = False
				yield []
			childVals = [a[node] for node in childNodes]
			childVals.sort()
			if requiredCnts == 0:
				val = 1
			else:
				val = childVals[requiredCnts - 1] + 1
			for zz in range(1, n + 1):
				if a[zz] >= val:
					a[zz] += 1
			childVals.append(val)
			childNodes.append(i)
			a[i] = val
			yield childNodes
		yield []
	possible = [True]
	a = [-1 for _ in range(n + 1)]
	dfs(root)
	if possible[0]:
		print('YES')
		ans = a[1:]
		oneLineArrayPrint(ans)
	else:
		print('NO')
	return
import sys
input = sys.stdin.buffer.readline

def oneLineArrayPrint(arr):
	print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
	print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
	print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
	return [int(x) for x in input().split()]

def makeArr(defaultVal, dimensionArr):
	dv = defaultVal
	da = dimensionArr
	if len(da) == 1:
		return [dv for _ in range(da[0])]
	else:
		return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(x, y):
	print('? {} {}'.format(x, y))
	sys.stdout.flush()
	return int(input())

def answerInteractive(ans):
	print('! {}'.format(ans))
	sys.stdout.flush()
inf = float('inf')
MOD = 10 ** 9 + 7
for _abc in range(1):
	main()


from sys import setrecursionlimit
setrecursionlimit(10 ** 6)
n = int(input())
c = [0 for i in range(n + 1)]
a = [0 for i in range(n + 1)]
g = [[] for i in range(n + 1)]

def dfs(x):
	List = []
	for i in g[x]:
		List += dfs(i)
	if c[x] > len(List):
		raise ValueError
	List.insert(c[x], x)
	return List
for i in range(1, n + 1):
	(pi, ci) = list(map(int, input().split(' ')))
	c[i] = ci
	g[pi].append(i)
try:
	ans = dfs(0)
	print('YES')
	for i in range(0, n + 1):
		a[ans[i]] = i
	for i in range(1, n + 1):
		print(a[i], end=' ')
except ValueError:
	print('NO')


import sys
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
import collections
from collections import defaultdict
n = int(input())
(c, root) = ([], 0)
graph = defaultdict(list)
for i in range(n):
	(a, b) = map(int, input().split())
	if a != 0:
		graph[i + 1].append(a)
		graph[a].append(i + 1)
	else:
		root = i + 1
	c.append(b)
ans = [0] * (n + 1)
store = [[] for _ in range(n + 1)]
OBSERVE = 0
CHECK = 1
stack = [(OBSERVE, root, 0)]
if n == 1 and c[0] == 0:
	sys.stdout.write('YES' + '\n')
	sys.stdout.write('1' + '\n')
else:
	while len(stack):
		(state, vertex, parent) = stack.pop()
		if state == OBSERVE:
			stack.append((CHECK, vertex, parent))
			for child in graph[vertex]:
				if child != parent:
					stack.append((OBSERVE, child, vertex))
		else:
			i = 0
			while i < len(graph[vertex]):
				if graph[vertex][i] != parent:
					if len(graph[graph[vertex][i]]) == 1 and graph[vertex][i] != root:
						store[graph[vertex][i]].append([i + 1, graph[vertex][i]])
					store[vertex] += store[graph[vertex][i]]
				i += 1
			store[vertex].sort()
			ok = True
			if c[vertex - 1] > len(store[vertex]):
				ok = False
				break
			else:
				if len(store[vertex]) > 0:
					if c[vertex - 1] != 0:
						store[vertex].insert(c[vertex - 1], [store[vertex][c[vertex - 1] - 1][0] + 1, vertex])
					else:
						store[vertex].insert(c[vertex - 1], [store[vertex][c[vertex - 1]][0], vertex])
				for ijk in range(len(store[vertex])):
					store[vertex][ijk][0] = ijk + 1
	if ok == True:
		for ij in store[root]:
			ans[ij[1]] = ij[0]
		sys.stdout.write('YES' + '\n')
		ans = ' '.join(map(str, ans[1:]))
		sys.stdout.write(ans + '\n')
	else:
		sys.stdout.write('NO' + '\n')


from collections import defaultdict, deque
from heapq import heappush, heappop
from itertools import permutations
import sys
import math
import bisect
import random

def LI():
	return [int(x) for x in sys.stdin.readline().split()]

def I():
	return int(sys.stdin.readline())

def LS():
	return [list(x) for x in sys.stdin.readline().split()]

def S():
	res = list(sys.stdin.readline())
	if res[-1] == '\n':
		return res[:-1]
	return res

def IR(n):
	return [I() for i in range(n)]

def LIR(n):
	return [LI() for i in range(n)]

def SR(n):
	return [S() for i in range(n)]

def LSR(n):
	return [LS() for i in range(n)]
sys.setrecursionlimit(1000000)
mod = 1000000007

def solve():

	def dfs(x):
		size[x] = 1
		for y in v[x]:
			size[x] += dfs(y)
		return size[x]

	def dfs2(x):
		cx = c[x]
		ans[x] = f[cx]
		f.pop(cx)
		for y in v[x]:
			dfs2(y)
	n = I()
	v = [[] for i in range(n)]
	c = [0] * n
	f = [[0, i] for i in range(n)]
	r = None
	for i in range(n):
		(a, b) = LI()
		a -= 1
		if a >= 0:
			f[a][0] += 1
			v[a].append(i)
		else:
			r = i
		c[i] = b
	size = [0] * n
	dfs(r)
	f = [i + 1 for i in range(n)]
	for i in range(n):
		if c[i] >= size[i]:
			print('NO')
			return
	ans = [0] * n
	dfs2(r)
	print('YES')
	print(*ans)
	return
solve()


import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
from collections import defaultdict, deque

def bfs(node):
	vis[node] = 1
	q = deque([node])
	order.append(node)
	while q:
		cur = q.popleft()
		for j in edge[cur]:
			if vis[j] == 0:
				child[cur].append(j)
				vis[j] = 1
				order.append(j)
				q.append(j)

def dfs(node):
	vis[node] = 1
	stack = [node]
	while stack:
		cur = stack.pop()
		ans[cur - 1] = lis[arr[cur]]
		lis.remove(ans[cur - 1])
		for j in edge[cur]:
			if vis[j] == 0:
				vis[j] = 1
				stack.append(j)
n = int(input())
edge = defaultdict(list)
child = defaultdict(list)
root = -1
arr = [-1] * (n + 1)
for i in range(n):
	(p, c) = list(map(int, input().split()))
	arr[i + 1] = c
	if p != 0:
		edge[p].append(i + 1)
		edge[i + 1].append(p)
	else:
		root = i + 1
subTreeSize = [1] * (n + 1)
vis = [0] * (n + 1)
order = []
bfs(root)
order.reverse()
for i in range(n):
	for j in child[order[i]]:
		subTreeSize[order[i]] += subTreeSize[j]
x = 0
for i in range(1, n + 1):
	if arr[i] > subTreeSize[i] - 1:
		x += 1
		break
if x == 1:
	print('NO')
else:
	print('YES')
	lis = []
	for i in range(n):
		lis.append(i + 1)
	vis = [0] * (n + 1)
	ans = [-1] * n
	dfs(root)
	print(' '.join((str(x) for x in ans)))


n = int(input())
parent = [0] * (n + 1)
great = [0] * (n + 1)
tree = [[] for _ in range(n + 1)]
root = 0
for i in range(1, n + 1):
	(p, c) = map(int, input().split())
	tree[p].append(i)
	if p == 0:
		root = i
	parent[i] = p
	great[i] = c
stack = [root]
ptr = [0]
accum = [[], []]
while len(stack) > 0:
	v = stack[-1]
	if ptr[-1] == len(tree[v]):
		if great[v] > len(accum[-1]):
			print('NO')
			exit()
		accum[-1].insert(great[v], v)
		accum[-2] += accum[-1]
		accum.pop()
		stack.pop()
		ptr.pop()
		continue
	to = tree[v][ptr[-1]]
	ptr[-1] += 1
	stack.append(to)
	ptr.append(0)
	accum.append([])
print('YES')
ans = [None] * n
for i in range(n):
	ans[accum[0][i] - 1] = str(i + 1)
print(' '.join(ans))


n = int(input())
adj_list = [[] for i in range(n + 1)]
c = [None]
for i in range(1, n + 1):
	(p_i, c_i) = map(int, input().split())
	c.append(c_i)
	adj_list[p_i].append(i)
sizes = [None for i in range(n + 1)]
values = [None for i in range(n + 1)]

def size(v):
	sizes[v] = 1
	for i in adj_list[v]:
		size(i)
		sizes[v] += sizes[i]
size(adj_list[0][0])

def get_ans(v):
	if len(adj_list[v]) == 0:
		if c[v] != 0:
			return None
		return [[1, v]]
	insert_at = c[v]
	merged_list = []
	current_size = 0
	for child in adj_list[v]:
		ans = get_ans(child)
		if ans == None:
			return None
		merged_list += [[x[0] + current_size, x[1]] for x in ans]
		current_size += sizes[child]
	if insert_at > len(merged_list) or insert_at < 0:
		return None
	new_list = merged_list[:insert_at]
	new_list.append([insert_at + 1, v])
	new_list += [[x[0] + 1, x[1]] for x in merged_list[insert_at:]]
	return new_list
x = get_ans(adj_list[0][0])
if x == None:
	print('NO')
else:
	print('YES')
	x.sort(key=lambda i: i[1])
	x = [str(a[0]) for a in x]
	print(' '.join(x))


import sys
zz = 1
sys.setrecursionlimit(10 ** 5)
if zz:
	input = sys.stdin.readline
else:
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('all.txt', 'w')
di = [[-1, 0], [1, 0], [0, 1], [0, -1]]

def fori(n):
	return [fi() for i in range(n)]

def inc(d, c, x=1):
	d[c] = d[c] + x if c in d else x

def ii():
	return input().rstrip()

def li():
	return [int(xx) for xx in input().split()]

def fli():
	return [float(x) for x in input().split()]

def comp(a, b):
	if a > b:
		return 2
	return 2 if a == b else 0

def gi():
	return [xx for xx in input().split()]

def gtc(tc, ans):
	print('Case #' + str(tc) + ':', ans)

def cil(n, m):
	return n // m + int(n % m > 0)

def fi():
	return int(input())

def pro(a):
	return reduce(lambda a, b: a * b, a)

def swap(a, i, j):
	(a[i], a[j]) = (a[j], a[i])

def si():
	return list(input().rstrip())

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

def gh():
	sys.stdout.flush()

def isvalid(i, j, n, m):
	return 0 <= i < n and 0 <= j < m

def bo(i):
	return ord(i) - ord('a')

def graph(n, m):
	for i in range(m):
		(x, y) = mi()
		a[x].append(y)
		a[y].append(x)
t = 1
uu = t
flag = 1

def dfs(i, p=-1, val=1):
	c = 0
	for j in a[i]:
		if j != p:
			c += dfs(j, i, val + c)
	if c < ch[i]:
		flag = 0
		return False
	c += 1
	for j in a[i]:
		if j != p:
			dfs2(j, i, val + ch[i])
	ans[i] = val + ch[i]
	return c

def dfs2(i, p=-1, val=1):
	if ans[i] >= val:
		ans[i] += 1
	for j in a[i]:
		if j != p:
			dfs2(j, i, val)
while t > 0:
	t -= 1
	n = fi()
	a = [[] for i in range(n + 1)]
	ch = [0] * (n + 1)
	ans = [0] * (n + 1)
	for i in range(n):
		(p, c) = mi()
		ch[i + 1] = c
		if p == 0:
			root = i + 1
		else:
			a[p].append(i + 1)
			a[i + 1].append(p)
	dfs(root)
	if flag == 0 or ans[1:].count(0):
		print('NO')
		continue
	print('YES')
	print(*ans[1:])


import io
import os
import sys
from collections import Counter, defaultdict, deque
sys.setrecursionlimit(10 ** 5)

def solve(N, PC):
	children = [[] for i in range(N)]
	cost = [None for i in range(N)]
	root = None
	for (i, (p, c)) in enumerate(PC):
		cost[i] = c
		p -= 1
		if p != -1:
			children[p].append(i)
		else:
			root = i

	def getOrder(node):
		ret = []
		for child in children[node]:
			ret.extend(getOrder(child))
		i = cost[node]
		if not 0 <= i <= len(ret):
			print('NO')
			exit()
		return ret[:i] + [node] + ret[i:]
	order = getOrder(root)
	nodeToVal = {}
	for (v, node) in enumerate(order):
		nodeToVal[node] = str(v + 1)
	return 'YES\n' + ' '.join((nodeToVal[i] for i in range(N)))
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
(N,) = [int(x) for x in input().split()]
PC = [[int(x) for x in input().split()] for i in range(N)]
ans = solve(N, PC)
print(ans)


import sys
sys.setrecursionlimit(10 ** 5)
input = sys.stdin.readline
n = int(input())
if n == 1:
	(p, c) = [int(item) for item in input().split()]
	if c == 0:
		print('YES')
		print(1)
	else:
		print('NO')
	exit()
edge = [[] for _ in range(n)]
par = None
cs = [0] * n
for i in range(n):
	(p, c) = [int(item) for item in input().split()]
	if p == 0:
		par = i
	else:
		edge[p - 1].append(i)
		edge[i].append(p - 1)
	cs[i] = c
cnt = 0

def dfs(p, v):
	global cnt
	if p != -1 and len(edge[v]) == 1:
		if cs[v] != 0:
			print('NO')
			exit()
		cnt += 1
		return [(cnt, v)]
	base = 0
	narr = []
	for nv in edge[v]:
		if p == nv:
			continue
		arr = dfs(v, nv)
		nbase = 0
		for (val, index) in arr:
			nbase = max(nbase, val)
			narr.append((val + base, index))
		base += nbase
	narr.sort()
	if cs[v] > len(narr):
		print('NO')
		exit()
	elif cs[v] == len(narr):
		narr.append((narr[-1][0] + 1, v))
		return narr
	if cs[v] == 0:
		tmp = []
		for (val, index) in narr:
			tmp.append((val + 1, index))
		narr = tmp[:]
		narr.append((narr[0][0] - 1, v))
		return narr
	if narr[cs[v]][0] - narr[cs[v] - 1][0] == 1:
		tmp = []
		for (val, index) in narr:
			tmp.append((val * 2, index))
		narr = tmp[:]
		narr.append((narr[cs[v] - 1][0] + 1, v))
	else:
		narr.append((narr[cs[v] - 1][0] + 1, v))
	return narr
ret = dfs(-1, par)
seen = set()
for (val, _) in ret:
	seen.add(val)
seen = list(seen)
seen.sort()
comp = dict()
for (i, item) in enumerate(seen):
	comp[item] = i + 1
ans = [0] * n
for (val, index) in ret:
	ans[index] = val
print('YES')
print(' '.join([str(comp[item]) for item in ans]))


n = int(input())
sz = {}
a = {}
vis = {}
c = {}
g = [[] for i in range(n + 10)]
flag = 1
for i in range(1, n + 1):
	(x, y) = map(int, input().split())
	c[i] = y
	g[x].append(i)

def dfs(u):
	global flag
	if u > 0:
		sum = 0
		for i in range(1, n + 1):
			if i not in vis:
				sum += 1
			if sum == c[u] + 1:
				a[u] = i
				vis[i] = 1
				break
	sz[u] = 1
	for i in range(len(g[u])):
		dfs(g[u][i])
		sz[u] += sz[g[u][i]]
	if u > 0 and sz[u] - 1 < c[u]:
		flag = 0
	return
dfs(0)
if flag == 0:
	print('No')
else:
	print('Yes')
	for i in range(1, 1 + n):
		print(a[i], end=' ')


from sys import setrecursionlimit
setrecursionlimit(10 ** 6)

def build(k):
	children = []
	for i in adj[k]:
		children += build(i)
	if C[k] > len(children):
		raise ValueError
	children.insert(C[k], k)
	return children
n = int(input())
adj = {i: [] for i in range(n + 1)}
C = [0 for i in range(n + 1)]
for i in range(1, n + 1):
	(p, c) = map(int, input().split())
	adj[p].append(i)
	C[i] = c
ans = [0 for _ in range(n + 1)]
try:
	for (val, i) in enumerate(build(0)):
		ans[i] = val + 1
	print('YES')
	print(*ans[1:])
except ValueError:
	print('NO')


import sys
input = sys.stdin.readline
n = int(input())
C = [(0, 0)] + [tuple(map(int, input().split())) for i in range(n)]
V = n + 1
EDGEIN = [0] * V
EDGEOUT = [-1] * V
for i in range(1, n + 1):
	(p, x) = C[i]
	if p != 0:
		EDGEIN[p] += 1
		EDGEOUT[i] = p
from collections import deque
QUE = deque()
ANS = [0] * V
USE = [[] for i in range(V)]
for i in range(1, V):
	if EDGEIN[i] == 0:
		QUE.append(i)
		ANS[i] = i
		if C[i][1] != 0:
			print('NO')
			sys.exit()
		USE[i].append(i)
TOP_SORT = []
while QUE:
	x = QUE.pop()
	TOP_SORT.append(x)
	to = EDGEOUT[x]
	EDGEIN[to] -= 1
	if EDGEIN[to] == 0:
		QUE.appendleft(to)
for po in TOP_SORT:
	to = EDGEOUT[po]
	if ANS[po] != 0:
		USE[to].extend(USE[po])
		USE[po] = []
	else:
		x = C[po][1]
		USE[po].sort()
		if len(USE[po]) < x:
			print('NO')
			sys.exit()
		elif len(USE[po]) == x:
			ANS[po] = max(ANS) + 1
			USE[to].append(ANS[po])
			USE[to].extend(USE[po])
			USE[po] = []
		else:
			if x != 0:
				AP = USE[po][x]
			else:
				AP = 1
			for i in range(1, n + 1):
				if ANS[i] >= AP:
					ANS[i] += 1
			for i in range(1, n + 1):
				for j in range(len(USE[i])):
					if USE[i][j] >= AP:
						USE[i][j] += 1
			ANS[po] = AP
			USE[to].append(ANS[po])
			USE[to].extend(USE[po])
			USE[po] = []
compression_dict = {a: ind for (ind, a) in enumerate(sorted(set(ANS)))}
ANS = [compression_dict[a] for a in ANS]
print('YES')
print(*ANS[1:])


import sys
input = sys.stdin.readline
from collections import deque
sys.setrecursionlimit(100000)

class Graph(object):

	def __init__(self, n, d):
		self.n = n
		self.graph = [[] for i in range(n)]
		self.parent = [-1 for i in range(n)]
		self.directed = d

	def addEdge(self, x, y):
		self.graph[x].append(y)
		if not self.directed:
			self.graph[y].append(x)

	def bfs(self, root):
		self.parent = [-1 for i in range(self.n)]
		queue = [root]
		queue = deque(queue)
		vis = [0] * self.n
		while len(queue) != 0:
			element = queue.popleft()
			vis[element] = 1
			for i in self.graph[element]:
				if vis[i] == 0:
					queue.append(i)
					self.parent[i] = element

	def dfs(self, root, ans):
		stack = [root]
		vis = [0] * self.n
		stack2 = []
		while len(stack) != 0:
			element = stack.pop()
			if vis[element]:
				continue
			vis[element] = 1
			stack2.append(element)
			for i in self.graph[element]:
				if vis[i] == 0:
					self.parent[i] = element
					stack.append(i)
		while len(stack2) != 0:
			element = stack2.pop()
			m = 0
			for i in self.graph[element]:
				if i != self.parent[element]:
					m += ans[i]
			ans[element] = m
		return ans

	def shortestpath(self, source, dest):
		self.bfs(source)
		path = [dest]
		while self.parent[path[-1]] != -1:
			path.append(parent[path[-1]])
		return path[::-1]

	def ifcycle(self):
		self.bfs(0)
		queue = [0]
		vis = [0] * n
		queue = deque(queue)
		while len(queue) != 0:
			element = queue.popleft()
			vis[element] = 1
			for i in graph[element]:
				if vis[i] == 1 and i != parent[element]:
					return True
				if vis[i] == 0:
					queue.append(i)
					vis[i] = 1
		return False

	def reroot(self, root, ans):
		stack = [root]
		vis = [0] * n
		while len(stack) != 0:
			e = stack[-1]
			if vis[e]:
				stack.pop()
				continue
			vis[e] = 1
			for i in graph[e]:
				if not vis[e]:
					stack.append(i)
			if self.parent[e] == -1:
				continue

	def calc(self, root):
		r = []
		for i in self.graph[root]:
			if i != self.parent[root]:
				temp = self.calc(i)
				if not temp:
					return False
				else:
					r += temp
		if v[root] > len(r):
			return False
		r.insert(v[root], root)
		return r
n = int(input())
g = Graph(n, False)
v = [0] * n
for i in range(n):
	(p, c) = map(int, input().split())
	v[i] = c
	if p != 0:
		g.addEdge(i, p - 1)
		g.parent[i] = p - 1
	else:
		root = i
a = g.calc(root)
if not a:
	print('NO')
	exit()
ans = [0] * n
for i in range(n):
	ans[a[i]] = i + 1
print('YES')
print(*ans)


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
n = int(input())
root = None
c = [None for x in range(n + 1)]
parent = [None for x in range(n + 1)]
for i in range(1, n + 1):
	(pi, ci) = [int(x) for x in input().split()]
	c[i] = ci
	if pi == 0:
		root = i
	parent[i] = pi

def parent_array_tograph(parent):
	l = len(parent)
	graph = dict()
	for i in range(1, l):
		if parent[i] not in graph:
			graph[parent[i]] = [i]
		else:
			graph[parent[i]].append(i)
	return graph
graph = parent_array_tograph(parent)

def dfs(graph, n, currnode):
	visited = [False for x in range(n + 1)]
	stack = [currnode]
	ans = []
	while stack:
		currnode = stack[-1]
		if visited[currnode] == False:
			visited[currnode] = True
			ans.append(currnode)
		if currnode in graph:
			for neighbour in graph[currnode]:
				if visited[neighbour] == False:
					visited[neighbour] = True
					stack.append(neighbour)
					ans.append(neighbour)
					break
			else:
				stack.pop()
		else:
			stack.pop()
	return ans
ans = dfs(graph, n, root)
result = [None for x in range(n + 1)]
value = [True for x in range(n + 1)]
notpossibe = False
for i in range(len(ans)):
	ci = c[ans[i]]
	index = 1
	while ci != 0 and index != n + 1:
		if value[index] == True:
			ci -= 1
			index += 1
		else:
			index += 1
	while True:
		if index == n + 1:
			notpossibe = True
			break
		if value[index] == True:
			value[index] = False
			result[ans[i]] = index
			break
		else:
			index += 1
	if notpossibe == True:
		break
if notpossibe == False:

	def dfs_count(graph, n, currnode):
		visited = [False for x in range(n + 1)]
		count = 0
		root = currnode
		stack = [currnode]
		ans = []
		while stack:
			currnode = stack[-1]
			if visited[currnode] == False:
				visited[currnode] = True
				if result[currnode] < result[root]:
					count += 1
			if currnode in graph:
				for neighbour in graph[currnode]:
					if visited[neighbour] == False:
						visited[neighbour] = True
						stack.append(neighbour)
						if result[neighbour] < result[root]:
							count += 1
						break
				else:
					stack.pop()
			else:
				stack.pop()
		return count
	for i in range(1, n + 1):
		if c[i] != dfs_count(graph, n, i):
			print('NO')
			break
	else:
		print('YES')
		print(*result[1:])
else:
	print('NO')


def ddfs(root):
	global count
	global flag
	visit = [0] * (n + 1)
	stack = [0, root]
	stack2 = []
	while len(stack) > 1:
		par = stack.pop()
		stack2.append(par)
		if visit[par]:
			continue
		visit[par] = 1
		for i in graph[par]:
			if visit[i] == 0:
				stack.append(i)
	visited = [0] * (n + 1)
	while len(stack2) > 1:
		q = stack2.pop()
		if count[q] < under[q]:
			flag = 1
		visited[q] = 1
		for i in graph[q]:
			if visited[i] == 0:
				count[i] += count[q] + 1

def dfs(root):
	stack = [root]
	visit = [0] * (n + 1)
	while stack:
		par = stack.pop()
		if visit[par]:
			continue
		yy = seg_queries(under[par] + 1, store - 1)
		final[par] = yy
		seg_update(store - 1 + yy)
		visit[par] = 1
		for i in graph[par]:
			if visit[i] == 0:
				stack.append(i)

def seg_update(yy):
	seg_tree[yy] = 0
	while yy > 1:
		yy = yy >> 1
		seg_tree[yy] = seg_tree[yy << 1] + seg_tree[(yy << 1) + 1]

def seg_queries(p, y):
	x = 1
	if seg_tree[x] < p:
		return -1
	while x <= y:
		if seg_tree[x << 1] >= p:
			x = x << 1
		else:
			p -= seg_tree[x << 1]
			x = (x << 1) + 1
	return x - y

def seg_build(x):
	while x >= 1:
		seg_tree[x] = seg_tree[x << 1] + seg_tree[(x << 1) + 1]
		x -= 1
n = int(input())
flag = 0
graph = [[] for i in range(n + 1)]
under = [0 for i in range(n + 1)]
for i in range(1, n + 1):
	(a, b) = map(int, input().split())
	under[i] = b
	if a == 0:
		root = i
	else:
		graph[a].append(i)
		graph[i].append(a)
count = [0] * (n + 1)
ddfs(root)
i = 1
while i < n:
	i = i << 1
store = i
seg_tree = [0 for j in range(store << 1)]
for j in range(store, store + n):
	seg_tree[j] = 1
final = [0 for i in range(n + 1)]
seg_build(store - 1)
dfs(root)
if flag == 0:
	print('YES')
	print(*final[1:])
else:
	print('NO')


import sys
import math
input = sys.stdin.readline
from functools import cmp_to_key

def pi():
	return int(input())

def pl():
	return int(input(), 16)

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

def ts():
	s = input()
	return list(s[:len(s) - 1])

def invr():
	return map(int, input().split())
mod = 998244353
f = []

def fact(n, m):
	global f
	f = [1 for i in range(n + 1)]
	f[0] = 1
	for i in range(1, n + 1):
		f[i] = f[i - 1] * i % m

def fast_mod_exp(a, b, m):
	res = 1
	while b > 0:
		if b & 1:
			res = res * a % m
		a = a * a % m
		b = b >> 1
	return res

def inverseMod(n, m):
	return fast_mod_exp(n, m - 2, m)

def ncr(n, r, m):
	if r == 0:
		return 1
	return f[n] * inverseMod(f[n - r], m) % m * inverseMod(f[r], m) % m
unused = {}

def main():
	B()

def checkPossibility(root, v, c):
	count = 0
	for i in range(len(v[root])):
		if not checkPossibility(v[root][i], v, c):
			return False
		count += c[v[root][i]]
	if c[root] <= count + len(v[root]):
		return True
	return False
b = True

def dfs(root, v, c):
	global b
	l = []
	for i in range(len(v[root])):
		l.extend(dfs(v[root][i], v, c))
	if c[root] > len(l):
		b = False
	l.insert(c[root], root)
	return l

def B():
	n = pi()
	v = [[] for i in range(n)]
	c = [0 for i in range(n)]
	root = -1
	for i in range(n):
		[p, ci] = ti()
		if p == 0:
			root = i
		else:
			v[p - 1].append(i)
		c[i] = ci
	l = dfs(root, v, c)
	ans = [0 for i in range(n)]
	if b:
		for i in range(n):
			ans[l[i]] = i + 1
		print('YES')
		print(*ans)
	else:
		print('NO')
main()


import sys
input = sys.stdin.readline
from bisect import bisect_left
n = int(input())
g = [[] for _ in range(n)]
c = [0] * n
for i in range(n):
	(p, c[i]) = map(int, input().split())
	if p != 0:
		g[p - 1].append(i)
	else:
		root = i
s = [root]
v = [0] * n
d = [[] for _ in range(n)]
idx = 0
while s:
	p = s.pop()
	if v[p] == 0:
		s.append(p)
		v[p] = 1
		for node in g[p]:
			s.append(node)
	else:
		for node in g[p]:
			d[p] += d[node]
		if len(d[p]) < c[p]:
			print('NO')
			exit(0)
		d[p].insert(c[p], p)
res = [0] * n
x = d[root]
for i in range(n):
	res[x[i]] = i + 1
print('YES')
print(*res)


from collections import deque
N = int(input())
X = [[] for i in range(N)]
P = [-1] * N
C = [0] * N
for i in range(N):
	(p, c) = map(int, input().split())
	C[i] = c
	if p:
		p -= 1
		P[i] = p
		X[p].append(i)
	else:
		rt = i
Q = deque([rt])
R = []
while Q:
	i = deque.popleft(Q)
	R.append(i)
	for a in X[i]:
		P[a] = i
		deque.append(Q, a)

def calc(i, cc, AA):
	B = {}
	k = 0
	for A in AA:
		for a in A:
			B[a] = A[a] + k
		k += len(A)
	if cc > len(B):
		print('NO')
		exit()
	B = {a: B[a] if B[a] < cc else B[a] + 1 for a in B}
	B[i] = cc
	return B
L = [[] for _ in range(N)]
for i in R[::-1]:
	K = []
	for j in X[i]:
		K.append(L[j])
	L[i] = calc(i, C[i], K)
print('YES')
ANS = [0] * N
for a in L[rt]:
	ANS[a] = L[rt][a] + 1
print(*ANS)


from __future__ import print_function
from collections import *
from sys import stdin
from heapq import *
from math import *
g = lambda : stdin.readline().strip()
gl = lambda : g().split()
gil = lambda : [int(var) for var in gl()]
gfl = lambda : [float(var) for var in gl()]
gcl = lambda : list(g())
gbs = lambda : [int(var) for var in g()]
mod = int(1000000000.0) + 7
inf = float('inf')
root = 1
(n,) = gil()
c = [0] * (n + 1)
children = [[] for _ in range(n + 1)]
for node in range(1, n + 1):
	(parent, ci) = gil()
	c[node] = ci
	if parent == 0:
		root = node
	children[parent].append(node)
depth = [0] * (n + 1)
st = [root]
while st:
	p = st.pop()
	for ch in children[p]:
		depth[ch] = depth[p] + 1
		st.append(ch)
nodes = list(range(1, n + 1))
nodes.sort(key=lambda x: depth[x])
lst = [None for _ in range(n + 1)]
while nodes:
	node = nodes.pop()
	down = []
	for ch in children[node]:
		for chi in lst[ch]:
			down.append(chi)
	if len(down) < c[node]:
		print('NO')
		exit()
	lst[node] = down
	down.insert(c[node], node)
val = [0] * (n + 1)
s = 1
for ch in lst[root]:
	val[ch] = s
	s += 1
print('YES')
print(*val[1:])


def push(g, u, v):
	if u not in g:
		g[u] = []
	g[u].append(v)

def build():
	S = [root]
	i = 0
	order = {}
	while i < len(S):
		u = S[i]
		if u in g:
			for v in g[u]:
				S.append(v)
		i += 1
	for u in S[::-1]:
		order[u] = []
		flg = False
		if u not in g:
			if cnt[u] == 0:
				order[u].append(u)
				flg = True
			else:
				return (False, root, order)
		else:
			cur = 0
			for v in g[u]:
				for x in order[v]:
					if cur == cnt[u]:
						flg = True
						order[u].append(u)
						cur += 1
					order[u].append(x)
					cur += 1
		if flg == False:
			if cnt[u] > len(order[u]):
				return (False, root, order)
			else:
				order[u].append(u)
	return (True, root, order)
n = int(input())
g = {}
cnt = {}
for i in range(1, n + 1):
	(p, c) = map(int, input().split())
	cnt[i] = c
	if p == 0:
		root = i
	else:
		push(g, p, i)
(flg, root, order) = build()
if flg == False:
	print('NO')
else:
	ans = [-1] * n
	for (val, u) in zip(list(range(n)), order[root]):
		ans[u - 1] = val + 1
	print('YES')
	print(' '.join([str(x) for x in ans]))


import sys
reader = (s.rstrip() for s in sys.stdin)
input = reader.__next__
from collections import deque
n = int(input())
c = [0] * n
p = [0] * n
cnt = [0] * n
for i in range(n):
	(pi, ci) = map(int, input().split())
	if pi:
		cnt[pi - 1] += 1
	p[i] = pi - 1
	c[i] = ci
que = deque()
for i in range(n):
	if cnt[i] == 0:
		que.append(i)
done = [0] * n
ans = None
rem = [[] for i in range(n)]
while que:
	i = que.pop()
	if done[i] or cnt[i]:
		continue
	done[i] = 1
	if len(rem[i]) < c[i]:
		print('NO')
		exit()
	new = rem[i][:c[i]] + [i] + rem[i][c[i]:]
	if p[i] != -1:
		rem[p[i]].extend(new)
		que.appendleft(p[i])
		cnt[p[i]] -= 1
	else:
		ans = new
ret = [0] * n
for i in range(n):
	ret[ans[i]] = i + 1
print('YES')
print(*ret)


class ordered_set:

	def __init__(self, N):
		self.N = N + 1
		self.tree = [0 for i in range(self.N)]

	def add(self, idx):
		while idx < self.N:
			self.tree[idx] += 1
			idx += idx & -idx

	def remove(self, idx):
		while idx < self.N:
			self.tree[idx] -= 1
			idx += idx & -idx

	def find_by_order(self, k):
		k -= 1
		idx = 0
		mask = 1
		while mask << 1 < self.N:
			mask <<= 1
		while mask:
			ti = idx + mask
			mask >>= 1
			if ti < self.N:
				if k >= self.tree[ti]:
					idx = ti
					k -= self.tree[ti]
		if k != 0:
			return -1
		return idx + 1

def subtree_size(cur, adj, size):
	size[cur] = 1
	for v in adj[cur]:
		if size[v] == 0:
			subtree_size(v, adj, size)
			size[cur] += size[v]

def fill(cur, adj, ost, c, a):
	a[cur] = ost.find_by_order(c[cur] + 1)
	ost.remove(a[cur])
	for v in adj[cur]:
		if a[v] == 0:
			fill(v, adj, ost, c, a)
n = int(input())
adj = [[] for i in range(n + 1)]
c = [0]
for i in range(1, n + 1):
	(p, ct) = map(int, input().split())
	adj[p].append(i)
	c.append(ct)
size = [0 for i in range(n + 1)]
subtree_size(adj[0][0], adj, size)
ok = True
for i in range(1, n + 1):
	if c[i] >= size[i]:
		ok = False
		break
if not ok:
	print('NO')
else:
	ost = ordered_set(n)
	for i in range(1, n + 1):
		ost.add(i)
	a = [0 for i in range(n + 1)]
	fill(adj[0][0], adj, ost, c, a)
	print('YES')
	for i in range(1, n + 1):
		print(a[i], end=' ')
	print()


import sys

class BIT:

	def __init__(self, n):
		self.n = n
		self.tree = [0] * n

	def _F(self, i):
		return i & i + 1

	def _getSum(self, r):
		result = 0
		while r >= 0:
			result += self.tree[r]
			r = self._F(r) - 1
		return result

	def getSum(self, l, r):
		return self._getSum(r) - self._getSum(l - 1)

	def _H(self, i):
		return i | i + 1

	def add(self, i, value=1):
		while i < self.n:
			self.tree[i] += value
			i = self._H(i)
reader = (line.rstrip() for line in sys.stdin)
input = reader.__next__
n = int(input())
cs = [0] * n
ps = [0] * n
children = [[] for _ in range(n)]
for i in range(n):
	(p, c) = map(int, input().split())
	if p > 0:
		ps[i] = p - 1
		children[p - 1].append(i)
	else:
		root = i
	cs[i] = c
visited = [False] * n
stack = [root]
prev = -1
rank = [1] * n
while stack:
	v = stack.pop()
	if not visited[v]:
		visited[v] = True
		for to in children[v]:
			stack.append(v)
			stack.append(to)
	else:
		rank[v] += rank[prev]
	prev = v
unused = BIT(n)
for i in range(n):
	unused.add(i)
ans = [None] * n
stack = [root]
while stack:
	v = stack.pop()
	kth = cs[v] + 1
	if kth > rank[v]:
		print('NO')
		sys.exit()
	L = -1
	R = n - 1
	while L + 1 < R:
		m = L + R >> 1
		if unused.getSum(0, m) < kth:
			L = m
		else:
			R = m
	ans[v] = R + 1
	unused.add(R, -1)
	stack.extend(children[v])
print('YES')
print(*ans)


from sys import stdin, stdout
import math
from bisect import bisect_left, bisect_right
input = lambda : stdin.readline().strip()
print = lambda s: stdout.write(s)
n = int(input())
children = {}
for i in range(n):
	children[i] = []
c = []
for i in range(n):
	(a, b) = map(int, input().split())
	if a != 0:
		children[a - 1].append(i)
	else:
		r = i
	c.append(b)

def sortTree(root):
	ls = []
	for i in children[root]:
		ls += sortTree(i)
	if c[root] <= len(ls):
		ls.insert(c[root], root)
	else:
		print('NO')
		exit()
	return ls
ls1 = sortTree(r)
ans = {}
for i in range(n):
	ans[ls1[i]] = i + 1
print('YES\n')
for i in range(n):
	print(str(ans[i]) + ' ')
print('\n')


from bisect import bisect_left as bl
from bisect import bisect_right as br
import heapq
import math
from collections import *
from functools import reduce, cmp_to_key
import sys
input = sys.stdin.readline

def factors(n):
	return sorted(list(set(reduce(list.__add__, ([i, n // i] for i in range(1, int(n ** 0.5) + 1) if n % i == 0)))))

def li():
	return [int(i) for i in input().rstrip('\n').split(' ')]

def st():
	return input().rstrip('\n')

def val():
	return int(input().rstrip('\n'))

def li2():
	return [i for i in input().rstrip('\n').split(' ')]

def li3():
	return [int(i) for i in input().rstrip('\n')]
va = 10 ** 7
helpl = defaultdict(deque)

def dfs(i):
	global va
	curr = []
	for j in d[i]:
		curr.extend(dfs(j))
	curr = sorted(list(curr))
	if len(curr) < c[i - 1]:
		print('NO')
		exit()
	if not len(curr):
		curr.append(va)
		helpl[va].append(i - 1)
		va -= 2000
	else:
		for j in range(c[i - 1]):
			helpl[curr[j] - 1].append(helpl[curr[j]].popleft())
			curr[j] -= 1
		for j in range(len(curr) - 1, c[i - 1] - 1, -1):
			helpl[curr[j] + 1].append(helpl[curr[j]].popleft())
			helpl[curr[j]] = deque()
			curr[j] += 1
		if c[i - 1] == len(curr):
			curr.append(curr[-1] + 1)
		else:
			curr = curr[:c[i - 1]] + [curr[c[i - 1]] - 1] + curr[c[i - 1]:]
		helpl[curr[c[i - 1]]].append(i - 1)
	return curr
n = val()
d = defaultdict(list)
c = []
a = [0 for i in range(n)]
for i in range(n):
	(x, y) = li()
	d[x].append(i + 1)
	c.append(y)
root = d[0][0]
d.pop(0)
for i in d:
	d[i] = sorted(d[i])
dfs(root)
curr = 1
for i in sorted(helpl):
	for j in helpl[i]:
		a[j] = curr
	if len(helpl[i]):
		curr += 1
print('YES')
print(*a)


from __future__ import division, print_function
from fractions import Fraction
import sys
import os
from io import BytesIO, IOBase
from functools import cmp_to_key
from heapq import *
from math import gcd, factorial, floor, ceil, sqrt
from copy import deepcopy
from collections import deque
from bisect import bisect_left as bl
from bisect import bisect_right as br
from bisect import bisect
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')

def print(*args, **kwargs):
	(sep, file) = (kwargs.pop('sep', ' '), kwargs.pop('file', sys.stdout))
	at_start = True
	for x in args:
		if not at_start:
			file.write(sep)
		file.write(str(x))
		at_start = False
	file.write(kwargs.pop('end', '\n'))
	if kwargs.pop('flush', False):
		file.flush()
if sys.version_info[0] < 3:
	(sys.stdin, sys.stdout) = (FastIO(sys.stdin), FastIO(sys.stdout))
else:
	(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
from types import GeneratorType

def iterative(f, stack=[]):

	def wrapped_func(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		to = f(*args, **kwargs)
		while True:
			if type(to) is GeneratorType:
				stack.append(to)
				to = next(to)
				continue
			stack.pop()
			if not stack:
				break
			to = stack[-1].send(to)
		return to
	return wrapped_func

def inp():
	return sys.stdin.readline().rstrip('\r\n')

def out(var):
	sys.stdout.write(str(var))

def lis():
	return list(map(int, inp().split()))

def stringlis():
	return list(map(str, inp().split()))

def sep():
	return map(int, inp().split())

def strsep():
	return map(str, inp().split())

def testcase(t):
	for pp in range(t):
		solve(pp)

def google(p):
	print('Case #' + str(p) + ': ', end='')

def lcm(a, b):
	return a * b // gcd(a, b)

def power(x, y, p):
	y %= p - 1
	res = 1
	x = x % p
	if x == 0:
		return 0
	while y > 0:
		if y & 1 == 1:
			res = res * x % p
		y = y >> 1
		x = x * x % p
	return res

def ncr(n, r):
	return factorial(n) // (factorial(r) * factorial(max(n - r, 1)))

def isPrime(n):
	if n <= 1:
		return False
	if n <= 3:
		return True
	if n % 2 == 0 or n % 3 == 0:
		return False
	i = 5
	while i * i <= n:
		if n % i == 0 or n % (i + 2) == 0:
			return False
		i = i + 6
	return True
inf = pow(10, 20)
mod = 10 ** 9 + 7

@iterative
def dfs(v, visited, st):
	visited[st] = 1
	for i in v[st]:
		if visited[i] == 0:
			ok = (yield dfs(v, visited, i))
			sub[st] += sub[i]
	yield True

@iterative
def dfs2(v, visited, st):
	visited[st] = 1
	arr = []
	global root
	for i in v[st]:
		if visited[i] == 0:
			ok = (yield dfs2(v, visited, i))
			arr += ok
	if len(v[st]) == 1 and st != root:
		arr.append([1, st])
	else:
		arr = sorted(arr)
		if c[st] == 0:
			for i in range(len(arr)):
				arr[i][0] += 1
			arr.append([1, st])
		elif c[st] >= len(arr):
			arr.append([arr[-1][0] + 1, st])
		else:
			for i in range(c[st], len(arr)):
				arr[i][0] += 2
			arr.append([arr[c[st] - 1][0] + 1, st])
	yield arr

def solve(case):
	n = int(inp())
	g = [[] for i in range(n)]
	global root
	for i in range(n):
		(a, b) = sep()
		if a != 0:
			a -= 1
			g[a].append(i)
			g[i].append(a)
		else:
			root = i
		c.append(b)
	vis = [0] * n
	dfs(g, vis, root)
	for i in range(n):
		if sub[i] - 1 < c[i]:
			print('NO')
			return
	print('YES')
	vis = [0] * n
	ans = dfs2(g, vis, root)
	out = [0] * n
	for (i, j) in ans:
		out[j] = i
	print(' '.join((str(out[i]) for i in range(n))))
root = 0
sub = [1] * 2020
c = []
testcase(1)


mod = 1000000007
eps = 10 ** (-9)

def main():
	import sys
	from collections import deque
	input = sys.stdin.readline
	N = int(input())
	par = [0] * (N + 1)
	child = [[] for _ in range(N + 1)]
	C = [0] * (N + 1)
	for v in range(1, N + 1):
		(p, c) = map(int, input().split())
		par[v] = p
		C[v] = c
		child[p].append(v)
		if p == 0:
			root = v
	que = deque()
	que.append(root)
	seq = []
	while que:
		v = que.popleft()
		seq.append(v)
		for u in child[v]:
			que.append(u)
	seq.reverse()
	size = [1] * (N + 1)
	for v in seq:
		for u in child[v]:
			size[v] += size[u]
	order = [[] for _ in range(N + 1)]
	for v in seq:
		if C[v] > size[v] - 1:
			print('NO')
			exit()
		for u in child[v]:
			order[v].extend(order[u])
		order[v].insert(C[v], v)
	print('YES')
	ans = [0] * N
	for (i, v) in enumerate(order[root]):
		ans[v - 1] = i + 1
	print(*ans)
main()


import sys
sys.setrecursionlimit(10 ** 6)
push = lambda : map(int, input().split())
from collections import defaultdict as Def
DSK = Def(list)
ok = True
n = int(input())
vi = [False] * (n + 1)
c = [0] * (n + 1)
NumChild = [0] * (n + 1)
res = [0] * (n + 1)

def DFS(u, pre):
	global ok
	NumChild[u] = 1
	cnt = 0
	for i in range(1, n + 1):
		cnt = cnt + (not vi[i])
		if cnt - 1 == c[u]:
			res[u] = i
			vi[i] = True
			break
	for v in DSK[u]:
		if v != pre:
			DFS(v, u)
			NumChild[u] += NumChild[v]
	if NumChild[u] - 1 < c[u]:
		ok = False
for i in range(1, n + 1):
	(p, c[i]) = push()
	if p != 0:
		DSK[p].append(i)
	else:
		root = i
DFS(root, 0)
if not ok:
	print('NO')
else:
	print('YES')
	print(*res[1:])


import math
import random
import heapq, bisect
import sys
from collections import deque, defaultdict
from fractions import Fraction
import sys
import threading
from collections import defaultdict
mod = 10 ** 9 + 7
mod1 = 998244353
import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

class TreeNode:

	def __init__(self, k, v):
		self.key = k
		self.value = v
		self.left = None
		self.right = None
		self.parent = None
		self.height = 1
		self.num_left = 1
		self.num_total = 1

class AvlTree:

	def __init__(self):
		self._tree = None

	def add(self, k, v):
		if not self._tree:
			self._tree = TreeNode(k, v)
			return
		node = self._add(k, v)
		if node:
			self._rebalance(node)

	def _add(self, k, v):
		node = self._tree
		while node:
			if k < node.key:
				if node.left:
					node = node.left
				else:
					node.left = TreeNode(k, v)
					node.left.parent = node
					return node.left
			elif node.key < k:
				if node.right:
					node = node.right
				else:
					node.right = TreeNode(k, v)
					node.right.parent = node
					return node.right
			else:
				node.value = v
				return

	@staticmethod
	def get_height(x):
		return x.height if x else 0

	@staticmethod
	def get_num_total(x):
		return x.num_total if x else 0

	def _rebalance(self, node):
		n = node
		while n:
			lh = self.get_height(n.left)
			rh = self.get_height(n.right)
			n.height = max(lh, rh) + 1
			balance_factor = lh - rh
			n.num_total = 1 + self.get_num_total(n.left) + self.get_num_total(n.right)
			n.num_left = 1 + self.get_num_total(n.left)
			if balance_factor > 1:
				if self.get_height(n.left.left) < self.get_height(n.left.right):
					self._rotate_left(n.left)
				self._rotate_right(n)
			elif balance_factor < -1:
				if self.get_height(n.right.right) < self.get_height(n.right.left):
					self._rotate_right(n.right)
				self._rotate_left(n)
			else:
				n = n.parent

	def _remove_one(self, node):
		replacement = node.left or node.right
		if node.parent:
			if AvlTree._is_left(node):
				node.parent.left = replacement
			else:
				node.parent.right = replacement
			replacement.parent = node.parent
			node.parent = None
		else:
			self._tree = replacement
			replacement.parent = None
		node.left = None
		node.right = None
		node.parent = None
		self._rebalance(replacement)

	def _remove_leaf(self, node):
		if node.parent:
			if AvlTree._is_left(node):
				node.parent.left = None
			else:
				node.parent.right = None
			self._rebalance(node.parent)
		else:
			self._tree = None
		node.parent = None
		node.left = None
		node.right = None

	def remove(self, k):
		node = self._get_node(k)
		if not node:
			return
		if AvlTree._is_leaf(node):
			self._remove_leaf(node)
			return
		if node.left and node.right:
			nxt = AvlTree._get_next(node)
			node.key = nxt.key
			node.value = nxt.value
			if self._is_leaf(nxt):
				self._remove_leaf(nxt)
			else:
				self._remove_one(nxt)
			self._rebalance(node)
		else:
			self._remove_one(node)

	def get(self, k):
		node = self._get_node(k)
		return node.value if node else -1

	def _get_node(self, k):
		if not self._tree:
			return None
		node = self._tree
		while node:
			if k < node.key:
				node = node.left
			elif node.key < k:
				node = node.right
			else:
				return node
		return None

	def get_at(self, pos):
		x = pos + 1
		node = self._tree
		while node:
			if x < node.num_left:
				node = node.left
			elif node.num_left < x:
				x -= node.num_left
				node = node.right
			else:
				return (node.key, node.value)
		raise IndexError('Out of ranges')

	@staticmethod
	def _is_left(node):
		return node.parent.left and node.parent.left == node

	@staticmethod
	def _is_leaf(node):
		return node.left is None and node.right is None

	def _rotate_right(self, node):
		if not node.parent:
			self._tree = node.left
			node.left.parent = None
		elif AvlTree._is_left(node):
			node.parent.left = node.left
			node.left.parent = node.parent
		else:
			node.parent.right = node.left
			node.left.parent = node.parent
		bk = node.left.right
		node.left.right = node
		node.parent = node.left
		node.left = bk
		if bk:
			bk.parent = node
		node.height = max(self.get_height(node.left), self.get_height(node.right)) + 1
		node.num_total = 1 + self.get_num_total(node.left) + self.get_num_total(node.right)
		node.num_left = 1 + self.get_num_total(node.left)

	def _rotate_left(self, node):
		if not node.parent:
			self._tree = node.right
			node.right.parent = None
		elif AvlTree._is_left(node):
			node.parent.left = node.right
			node.right.parent = node.parent
		else:
			node.parent.right = node.right
			node.right.parent = node.parent
		bk = node.right.left
		node.right.left = node
		node.parent = node.right
		node.right = bk
		if bk:
			bk.parent = node
		node.height = max(self.get_height(node.left), self.get_height(node.right)) + 1
		node.num_total = 1 + self.get_num_total(node.left) + self.get_num_total(node.right)
		node.num_left = 1 + self.get_num_total(node.left)

	@staticmethod
	def _get_next(node):
		if not node.right:
			return node.parent
		n = node.right
		while n.left:
			n = n.left
		return n

class SegmentTree1:

	def __init__(self, data, default=2 ** 30, func=lambda a, b: min(a, b)):
		self._default = default
		self._func = func
		self._len = len(data)
		self._size = _size = 1 << (self._len - 1).bit_length()
		self.data = [default] * (2 * _size)
		self.data[_size:_size + self._len] = data
		for i in reversed(range(_size)):
			self.data[i] = func(self.data[i + i], self.data[i + i + 1])

	def __delitem__(self, idx):
		self[idx] = self._default

	def __getitem__(self, idx):
		return self.data[idx + self._size]

	def __setitem__(self, idx, value):
		idx += self._size
		self.data[idx] = value
		idx >>= 1
		while idx:
			self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
			idx >>= 1

	def __len__(self):
		return self._len

	def query(self, start, stop):
		if start == stop:
			return self.__getitem__(start)
		stop += 1
		start += self._size
		stop += self._size
		res = self._default
		while start < stop:
			if start & 1:
				res = self._func(res, self.data[start])
				start += 1
			if stop & 1:
				stop -= 1
				res = self._func(res, self.data[stop])
			start >>= 1
			stop >>= 1
		return res

	def __repr__(self):
		return 'SegmentTree({0})'.format(self.data)

class SegmentTree:

	def __init__(self, data, default=0, func=lambda a, b: a + b):
		self._default = default
		self._func = func
		self._len = len(data)
		self._size = _size = 1 << (self._len - 1).bit_length()
		self.data = [default] * (2 * _size)
		self.data[_size:_size + self._len] = data
		for i in reversed(range(_size)):
			self.data[i] = func(self.data[i + i], self.data[i + i + 1])

	def __delitem__(self, idx):
		self[idx] = self._default

	def __getitem__(self, idx):
		return self.data[idx + self._size]

	def __setitem__(self, idx, value):
		idx += self._size
		self.data[idx] = value
		idx >>= 1
		while idx:
			self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
			idx >>= 1

	def __len__(self):
		return self._len

	def query(self, start, stop):
		if start == stop:
			return self.__getitem__(start)
		stop += 1
		start += self._size
		stop += self._size
		res = self._default
		while start < stop:
			if start & 1:
				res = self._func(res, self.data[start])
				start += 1
			if stop & 1:
				stop -= 1
				res = self._func(res, self.data[stop])
			start >>= 1
			stop >>= 1
		return res

	def __repr__(self):
		return 'SegmentTree({0})'.format(self.data)

class Factorial:

	def __init__(self, MOD):
		self.MOD = MOD
		self.factorials = [1, 1]
		self.invModulos = [0, 1]
		self.invFactorial_ = [1, 1]

	def calc(self, n):
		if n <= -1:
			print('Invalid argument to calculate n!')
			print('n must be non-negative value. But the argument was ' + str(n))
			exit()
		if n < len(self.factorials):
			return self.factorials[n]
		nextArr = [0] * (n + 1 - len(self.factorials))
		initialI = len(self.factorials)
		prev = self.factorials[-1]
		m = self.MOD
		for i in range(initialI, n + 1):
			prev = nextArr[i - initialI] = prev * i % m
		self.factorials += nextArr
		return self.factorials[n]

	def inv(self, n):
		if n <= -1:
			print('Invalid argument to calculate n^(-1)')
			print('n must be non-negative value. But the argument was ' + str(n))
			exit()
		p = self.MOD
		pi = n % p
		if pi < len(self.invModulos):
			return self.invModulos[pi]
		nextArr = [0] * (n + 1 - len(self.invModulos))
		initialI = len(self.invModulos)
		for i in range(initialI, min(p, n + 1)):
			next = -self.invModulos[p % i] * (p // i) % p
			self.invModulos.append(next)
		return self.invModulos[pi]

	def invFactorial(self, n):
		if n <= -1:
			print('Invalid argument to calculate (n^(-1))!')
			print('n must be non-negative value. But the argument was ' + str(n))
			exit()
		if n < len(self.invFactorial_):
			return self.invFactorial_[n]
		self.inv(n)
		nextArr = [0] * (n + 1 - len(self.invFactorial_))
		initialI = len(self.invFactorial_)
		prev = self.invFactorial_[-1]
		p = self.MOD
		for i in range(initialI, n + 1):
			prev = nextArr[i - initialI] = prev * self.invModulos[i % p] % p
		self.invFactorial_ += nextArr
		return self.invFactorial_[n]

class Combination:

	def __init__(self, MOD):
		self.MOD = MOD
		self.factorial = Factorial(MOD)

	def ncr(self, n, k):
		if k < 0 or n < k:
			return 0
		k = min(k, n - k)
		f = self.factorial
		return f.calc(n) * f.invFactorial(max(n - k, k)) * f.invFactorial(min(k, n - k)) % self.MOD

def powm(a, n, m):
	if a == 1 or n == 0:
		return 1
	if n % 2 == 0:
		s = powm(a, n // 2, m)
		return s * s % m
	else:
		return a * powm(a, n - 1, m) % m

def sort_list(list1, list2):
	zipped_pairs = zip(list2, list1)
	z = [x for (_, x) in sorted(zipped_pairs)]
	return z

def product(l):
	por = 1
	for i in range(len(l)):
		por *= l[i]
	return por

def binarySearchCount(arr, n, key):
	left = 0
	right = n - 1
	count = 0
	while left <= right:
		mid = int((right + left) / 2)
		if arr[mid] < key:
			count = mid + 1
			left = mid + 1
		else:
			right = mid - 1
	return count

def countdig(n):
	c = 0
	while n > 0:
		n //= 10
		c += 1
	return c

def binary(x, length):
	y = bin(x)[2:]
	return y if len(y) >= length else '0' * (length - len(y)) + y

def countGreater(n, k):
	l = 0
	r = n - 1
	leftGreater = n
	while l <= r:
		m = int(l + (r - l) / 2)
		if a.get_at(m)[0] >= k:
			leftGreater = m
			r = m - 1
		else:
			l = m + 1
	return n - leftGreater

class TrieNode:

	def __init__(self):
		self.children = [None] * 26
		self.isEndOfWord = False

class Trie:

	def __init__(self):
		self.root = self.getNode()

	def getNode(self):
		return TrieNode()

	def _charToIndex(self, ch):
		return ord(ch) - ord('a')

	def insert(self, key):
		pCrawl = self.root
		length = len(key)
		for level in range(length):
			index = self._charToIndex(key[level])
			if not pCrawl.children[index]:
				pCrawl.children[index] = self.getNode()
			pCrawl = pCrawl.children[index]
		pCrawl.isEndOfWord = True

	def search(self, key):
		pCrawl = self.root
		length = len(key)
		for level in range(length):
			index = self._charToIndex(key[level])
			if not pCrawl.children[index]:
				return False
			pCrawl = pCrawl.children[index]
		return pCrawl != None and pCrawl.isEndOfWord

class Node:

	def __init__(self, data):
		self.data = data
		self.count = 0
		self.left = None
		self.right = None

class BinaryTrie:

	def __init__(self):
		self.root = Node(0)

	def insert(self, pre_xor):
		self.temp = self.root
		for i in range(31, -1, -1):
			val = pre_xor & 1 << i
			if val:
				if not self.temp.right:
					self.temp.right = Node(0)
				self.temp = self.temp.right
				self.temp.count += 1
			if not val:
				if not self.temp.left:
					self.temp.left = Node(0)
				self.temp = self.temp.left
				self.temp.count += 1
		self.temp.data = pre_xor

	def query(self, xor):
		self.temp = self.root
		for i in range(31, -1, -1):
			val = xor & 1 << i
			if not val:
				if self.temp.left and self.temp.left.count > 0:
					self.temp = self.temp.left
				elif self.temp.right:
					self.temp = self.temp.right
			elif self.temp.right and self.temp.right.count > 0:
				self.temp = self.temp.right
			elif self.temp.left:
				self.temp = self.temp.left
			self.temp.count -= 1
		return xor ^ self.temp.data
for ik in range(1):
	n = int(input())
	graph = defaultdict(list)
	l = [1 for i in range(n + 1)]
	l[0] = 0
	s = SegmentTree(l)
	ans = defaultdict(int)
	ro = 0
	c = defaultdict(int)
	for i in range(n):
		(e, c[i]) = map(int, input().split())
		if e == 0:
			ro = i
			continue
		(a, b) = (i + 1, e)
		graph[a - 1].append(b - 1)
		graph[b - 1].append(a - 1)
	visited = [False] * n

	def find(k):
		st = 0
		end = n
		ans = n
		while st <= end:
			mid = (st + end) // 2
			if s.query(0, mid) >= k:
				ans = mid
				end = mid - 1
			else:
				st = mid + 1
		return ans

	def dfs(v):
		visited[v] = True
		sub = []
		ans[v] = find(c[v] + 1)
		s.__setitem__(ans[v], 0)
		for i in graph[v]:
			if visited[i] == False:
				sub += dfs(i)
		if c[v] > len(sub):
			print('NO')
			sys.exit(0)
		return sub + [v]
	dfs(ro)
	print('YES')
	for i in range(n):
		print(ans[i], end=' ')


n = int(input())
graph = [[] for _ in range(n + 1)]
ci = [0]

def solve(x):
	rst = []
	if graph[x]:
		for s in graph[x]:
			tmp = solve(s)
			rst.extend(tmp)
			del tmp
	if len(rst) < ci[x]:
		raise ValueError
	rst.insert(ci[x], x)
	return rst
for i in range(1, n + 1):
	(p, c) = map(int, input().split())
	graph[p].append(i)
	ci.append(c)
try:
	ans = solve(graph[0][0])
except ValueError:
	print('NO')
else:
	print('YES')
	for i in range(1, n + 1):
		print(ans.index(i) + 1, end=' ')


from collections import defaultdict

def dfs(g, node, parent, trees):
	l = 0
	for i in g[node]:
		if i != parent:
			l += dfs(g, i, node, trees)
	trees[node] = l
	return l + 1

def dfs2(g, node, Small, answer, C, trees):
	answer[node] = Small[C[node]]
	supersmall = []
	for i in range(len(Small)):
		if i != C[node]:
			supersmall.append(Small[i])
	cnts = 0
	for i in g[node]:
		u = []
		for j in range(trees[i]):
			u.append(supersmall[cnts])
			cnts += 1
		dfs2(g, i, u, answer, C, trees)
n = int(input())
root = None
C = [0] * n
g = defaultdict(list)
for i in range(n):
	(parent, c) = map(int, input().strip().split())
	if parent == 0:
		root = i
	else:
		g[parent - 1].append(i)
	C[i] = c
trees = [0] * n
dfs(g, root, -1, trees)
check = list(map(lambda x, y: x - y, trees, C))
for i in check:
	if i < 0:
		print('NO')
		exit(0)
ans = [0] * n
small = [*range(1, n + 1)]
trees = list(map(lambda s: s + 1, trees))
dfs2(g, root, small, ans, C, trees)
print('YES')
print(*ans)


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from collections import deque, defaultdict
n = int(input())
tree = [[] for s in range(n)]
nums = []
root = 0
for s in range(n):
	(p, c) = map(int, input().split())
	p -= 1
	if p != -1:
		tree[p].append(s)
		tree[s].append(p)
	else:
		root = s
	nums.append(c)
if n == 1:
	if nums[0] == 0:
		print('YES')
		print(1)
	else:
		print('NO')
else:
	dp = {}
	queue = deque([root])
	vis = set([root])
	depth = defaultdict(list)
	dd = {}
	cv = 0
	pr = 1
	while len(queue) > 0:
		v0 = queue.popleft()
		for s in tree[v0]:
			if not s in vis:
				queue.append(s)
				vis.add(s)
		depth[cv].append(v0)
		dd[v0] = cv
		pr -= 1
		if pr == 0:
			pr = len(queue)
			cv += 1
	cv -= 1
	broke = False
	while cv >= 0:
		for node in depth[cv]:
			count = nums[node]
			if len(tree[node]) == 1 and node != root:
				dp[node] = [(1, node)]
				if count > 0:
					broke = True
					break
			elif len(tree[node]) == 2 and node != root:
				for s in tree[node]:
					if dd[s] > dd[node]:
						dp[node] = dp[s].copy()
				if count > len(dp[node]):
					broke = True
					break
				elif count == 0:
					dp[node].insert(0, (1, node))
				else:
					dp[node].insert(nums[node], (dp[node][nums[node] - 1][0] + 1, node))
				for s in range(nums[node] + 1, len(dp[node])):
					dp[node][s] = (dp[node][s][0] + 1, dp[node][s][1])
			else:
				merge = []
				new = []
				for s in tree[node]:
					if dd[s] > dd[node]:
						merge.append(dp[s].copy())
				new = merge.pop()
				while len(merge) > 0:
					temp = []
					nxt = merge.pop()
					new.reverse()
					nxt.reverse()
					while len(new) > 0 or len(nxt) > 0:
						if len(new) > 0 and len(nxt) > 0:
							if new[-1][0] <= nxt[-1][0]:
								temp.append(new.pop())
							else:
								temp.append(nxt.pop())
						elif len(new) > 0:
							temp.append(new.pop())
						else:
							temp.append(nxt.pop())
					new = temp.copy()
					temp = []
				dp[node] = new
				if count > len(dp[node]):
					broke = True
					break
				elif count == 0:
					dp[node].insert(0, (1, node))
				else:
					dp[node].insert(nums[node], (dp[node][nums[node] - 1][0] + 1, node))
				for s in range(nums[node] + 1, len(dp[node])):
					dp[node][s] = (dp[node][s][0] + 1, dp[node][s][1])
			if broke == True:
				break
		if broke == True:
			break
		cv -= 1
	if broke == True:
		print('NO')
	else:
		print('YES')
		ans = [0 for s in range(n)]
		for s in dp[root]:
			ans[s[1]] = s[0]
		print(*ans)


from sys import stdin, stderr, setrecursionlimit

def rl():
	return [int(w) for w in stdin.readline().split()]
setrecursionlimit(1000000)
(n,) = rl()
children = [[] for i in range(n + 1)]
c = [0]
for i in range(1, n + 1):
	(pi, ci) = rl()
	c.append(ci)
	children[pi].append(i)

def build(root):
	r = []
	for ch in children[root]:
		r += build(ch)
	if c[root] > len(r):
		raise ValueError()
	r.insert(c[root], root)
	return r
a = [0] * (n + 1)
try:
	for (x, i) in enumerate(build(0)):
		a[i] = x + 1
	print('YES')
	print(*a[1:])
except ValueError:
	print('NO')