{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N+,O-,P+,Q+,R+,S+,T-,U-,V+,W-,X+,Y+,Z1}
{$APPTYPE CONSOLE}
uses
    sysutils, math, testlib;

const
    NMAX = 1500;

type
    int = longint;
    point = record
        x, y: int;
    end;

function addp(p: int; const A: point; q: int; const B: point): point;
begin
    result.x := p * A.x + q * B.x;
    result.y := p * A.y + q * B.y;
end;

function cp(const A, B: point): int;
begin
    result := sign(A.x * B.y - A.y * B.x);
end;

function cross(const A1, B1, A2, B2: point): int;
    var
        r1, r2: int;
begin
    result := 0;
    if max(A1.x, B1.x) < min(A2.x, B2.x) then exit;
    if max(A1.y, B1.y) < min(A2.y, B2.y) then exit;
    if max(A2.x, B2.x) < min(A1.x, B1.x) then exit;
    if max(A2.y, B2.y) < min(A1.y, B1.y) then exit;
    r1 := cp(addp(1, B1, -1, A1), addp(1, A2, -1, A1)) * cp(addp(1, B1, -1, A1), addp(1, B2, -1, A1));
    r2 := cp(addp(1, B2, -1, A2), addp(1, A1, -1, A2)) * cp(addp(1, B2, -1, A2), addp(1, B1, -1, A2));
    if (r1 > 0) or (r2 > 0) then exit;
    result := 2 - ord(r1 * r2 = 0);
end;

var
    n: int;
    i: int;
    p: array [1..NMAX] of point;
    e: array [1..NMAX - 1] of point;
    name: array [1..NMAX] of string;
    used: array [1..NMAX] of boolean;
    tmp, curName: string;
    j, idx: int;
    t2c: array [1..NMAX] of int;
    code: integer;
begin
    n := inf.readInteger();
    assert((2 <= n) and (n <= 1500));
    inf.nextLine();

    for i := 1 to n do begin
        name[i] := inf.readString();
        assert(length(name[i]) >= 1);
        assert(length(name[i]) <= 60);
        assert(name[i] = trim(name[i]));
        for j := 1 to i - 1 do
            assert(name[i] <> name[j]);
        for j := 1 to length(name[i]) do begin
            assert(ord(name[i][j]) >= 32);
            assert(ord(name[i][j]) <= 255);
        end;
        p[i].x := inf.readInteger();
        assert(abs(p[i].x) <= 10000);
        p[i].y := inf.readInteger();
        assert(abs(p[i].y) <= 10000);
        inf.nextLine;
    end;
    for i := 1 to n - 1 do begin
        e[i].x := inf.readInteger();
        e[i].y := inf.readInteger();
        assert(e[i].x >= 1);
        assert(e[i].y >= 1);
        assert(e[i].x <= n);
        assert(e[i].y <= n);
        assert(e[i].x <> e[i].y);
    end;

    for i := 1 to n do begin
        curName := ouf.readString();
        if curName = 'No solution' then begin
            quit(_wa, '"No solution" found, but solution exists');
        end;
        idx := -1;
        for j := 1 to n do
            if name[j] = curName then begin
                if used[j] then
                     quit(_wa, format('city %s is used twice', [name[j]]));
                used[j] := true;
                idx := j;
            end;
        if (idx < 0) or (curName = '') then
            quit(_wa, format('%s is not a valid city name', [curName]));
        t2c[i] := idx;
    end;

    for i := 1 to n - 1 do
        for j := i + 1 to n - 1 do
            if cross(p[t2c[e[i].x]], p[t2c[e[i].y]],
                p[t2c[e[j].x]], p[t2c[e[j].y]]) = 2 then begin
                quit(_wa, format('edges %d and %d cross', [i, j]));
            end;

    quit(_ok, format('%d cities', [n]));
end.