import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.StringTokenizer;

/**
 * ICPC Central Europe Regional Contest 2018
 * Sample solution: Trees Gump
 * 
 * This solution recursively maps subtrees to subsets of nodes based on their
 * angle ordering. This guarantees that no cross-subtree edges intersect,
 * which, if applied recursively, avoids intersections at all.
 * 
 * @author Martin Kacer
 */
public class TreeGumpMK {
	StringTokenizer st = new StringTokenizer("");
	BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
	boolean hasNextToken() {
		try {
			while (!st.hasMoreTokens()) {
				String line = input.readLine();
				if (line == null) return false;
				st = new StringTokenizer(line);
			}
		} catch (IOException ex) { throw new RuntimeException(ex); }
		return true;
	}
	String nextToken() {
		return (!hasNextToken()) ? null : st.nextToken();
	}
	int nextInt() {
		return Integer.parseInt(nextToken());
	}	
	public static void main(String[] args) {
		new TreeGumpMK().run();
	}
	
	static class Point { final int idx; final long x, y; Point(int idx, long x, long y) { this.idx = idx; this.x = x; this.y = y; }
	@Override public String toString() { return "[" + x + "," + y + "]";}
	}
	
	static class CompareByAngle implements Comparator<Point> {
		final Point origin; final double a0;
		CompareByAngle(Point origin, Point prev) { this.origin = origin; this.a0 = (prev == null) ? -100 : Math.atan2(prev.y - origin.y, prev.x - origin.x); }
		public int compare(Point p1, Point p2) {
			double a1 = Math.atan2(p1.y - origin.y, p1.x - origin.x), a2 = Math.atan2(p2.y - origin.y, p2.x - origin.x);
			if (a1 > a0 && a2 < a0) return -1; else if (a1 < a0 && a2 > a0) return +1;
			return Double.compare(a1, a2);
		}
	}
	
	List<List<Integer>> graph;
	Point[] points;
	int[] mapping, subsize;
	
	void run() {
		int n = nextInt();
		graph = new ArrayList<>(n);
		for (int i = 0; i < n; ++i) graph.add(new ArrayList<>());
		for (int i = 1; i < n; ++i) {
			int a = nextInt(), b = nextInt();
			graph.get(a).add(b); graph.get(b).add(a);
		}
		points = new Point[n]; mapping = new int[n]; subsize = new int[n];
		for (int i = 0 ; i < n; ++i) points[i] = new Point(i, nextInt(), nextInt());
		Arrays.sort(points, 0, n, (a,b) -> Long.compare(a.y, b.y));
		calcSubSize(0, -1);
		process(0, -1, 0, n);
		for (int a = 0; a < n; ++a)
			for (int b : graph.get(a)) if (a < b) {
				System.out.println(points[mapping[a]].idx + " " + points[mapping[b]].idx);
			}
	}
	
	int calcSubSize(int root, int parent) {
		int res = 1;
		for (int n : graph.get(root)) if (n != parent)
			res += calcSubSize(n, root);
		return subsize[root] = res;
	}
	
	void process(int root, int parent, int fromIdx, int toIdx) {
		mapping[root] = fromIdx;
		int curidx = fromIdx+1;
		Arrays.sort(points, curidx, toIdx, new CompareByAngle(points[fromIdx], (parent < 0) ? null : points[mapping[parent]]));
		for (int n : graph.get(root)) if (n != parent) {
			process(n, root, curidx, curidx + subsize[n]);
			curidx += subsize[n];
		}
	}
}
