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 ≤ n ≤ 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 ≤ p_i ≤ n; 0 ≤ c_i ≤ 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 ≤ a_i ≤ {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
import java.io.*;
import java.util.*;

@SuppressWarnings("unchecked")
public class Main {
	static int[] p, c, a, size;
	static List<Integer>[] list;
	static SegmentTree tree;
	static boolean[] check;

	static class SegmentTree {
		int n;
		int[] t;

		SegmentTree(int n) {
			this.n = n;
			int h = (int)Math.ceil(Math.log(n) / Math.log(2));
			t = new int[1 << (h + 1)];
			init(1, 0, n - 1);
		}

		int init(int n, int s, int e) {
			if (s == e) {
				return t[n] = 1;
			} else {
				return t[n] = init(2 * n, s, (s + e) / 2) + init(2 * n + 1, (s + e) / 2 + 1, e);
			}
		}

		void update(int idx, int diff) {
			update(1, 0, n - 1, idx, diff);
		}

		void update(int n, int s, int e, int idx, int diff) {
			if (idx < s || e < idx) {
				return;
			}
			t[n] += diff;
			if (s != e) {
				update(2 * n, s, (s + e) / 2, idx, diff);
				update(2 * n + 1, (s + e) / 2 + 1, e, idx, diff);
			}
		}

		int search(int k) {
			return t[1] > k ? search(1, 0, n - 1, k) : -1;
		}

		int search(int n, int s, int e, int k) {
			if (s == e) {
				return s;
			}
			if (t[2 * n] > k) {
				return search(2 * n, s, (s + e) / 2, k);
			} else {
				return search(2 * n + 1, (s + e) / 2 + 1, e, k - t[2 * n]);
			}
		}
	}

	public static int dfs1(int x) {
		check[x] = true;
		for (int y : list[x]) {
			if (!check[y]) {
				check[y] = true;
				size[x] += dfs1(y) + 1;
			}
		}
		if (size[x] < c[x]) {
			System.out.println("NO");
			System.exit(0);
		}
		return size[x];
	}

	public static void dfs2(int x) {
		check[x] = true;
		int res = tree.search(c[x]);
		a[x] = res + 1;
		tree.update(res, -1);
		for (int y : list[x]) {
			if (!check[y]) {
				check[y] = true;
				dfs2(y);
			}
		}
	}

	public static void main(String[] args) {
		InputReader in = new InputReader();
		StringBuilder out = new StringBuilder();

		int N = in.nextInt();
		p = new int[N];
		c = new int[N];
		a = new int[N];
		list = new List[N];
		for (int i = 0; i < N; i++) {
			list[i] = new ArrayList<>();
		}
		int root = -1;
		for (int i = 0; i < N; i++) {
			p[i] = in.nextInt() - 1;
			c[i] = in.nextInt();
			if (p[i] == -1) {
				root = i;
			} else {
				list[i].add(p[i]);
				list[p[i]].add(i);
			}
		}

		check = new boolean[N];
		size = new int[N];
		dfs1(root);

		tree = new SegmentTree(N);
		Arrays.fill(check, false);
		dfs2(root);

		out.append("YES\n");
		for (int i = 0; i < N; i++) {
			out.append(a[i] + " ");
		}
		out.setCharAt(out.length() - 1, '\n');

		System.out.print(out);
	}

	static class InputReader {
		public BufferedReader reader;
		public StringTokenizer st;

		public InputReader() {
			reader = new BufferedReader(new InputStreamReader(System.in));
		}

		public String next() {
			while (st == null || !st.hasMoreTokens()) {
				st = new StringTokenizer(nextLine());
			}
			return st.nextToken();
		}

		public String nextLine() {
			try {
				return reader.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}
	}
}
