import ru.ifmo.testlib.Checker;
import ru.ifmo.testlib.InStream;
import ru.ifmo.testlib.Outcome;

import static ru.ifmo.testlib.Outcome.Type.*;

public class Check implements Checker {

    public Outcome test(InStream inf, InStream ouf, InStream ans) {
        int size = ouf.nextInt();
        if (size < 0 || size > 100000) {
        	throw new Outcome(PE, String.format("Invalid number of vertices %d", size));
        }
        int[] parent = new int[size];
        char[] label = new char[size];
        int rootCount = 0;
        for (int i = 0; i < size; i++) {
            parent[i] = ouf.nextInt() - 1;
            if (parent[i] < -1 || parent[i] >= size)
                throw new Outcome(PE, String.format("Parent with incorrect index %d", parent[i] + 1));
            if (parent[i] == -1) {
                rootCount++;
            } else {
                String token = ouf.nextToken();
                if (token.length() > 1 || token.charAt(0) < 'a' || token.charAt(0) > 'z')
                    throw new Outcome(PE, String.format("Invalid label %s", token));
                label[i] = token.charAt(0);
            }
        }
        if (!ouf.seekEoF())
            throw new Outcome(PE, "Extra data in output file");
        // ---- PE check done, check correctness ----
        if (rootCount > 1)
            throw new Outcome(WA, "Tree has more then one root");

        int[] processed = new int[size];
        for (int i = 0; i < size; i++) {
            if (processed[i] != 0)
                continue;
            int current = i;
            do {
                processed[current] = 1;
                current = parent[current];
            } while (current != -1 && processed[current] == 0);
            if (current == -1 || processed[current] == 2) {
                current = i;
                do {
                    processed[current] = 2;
                    current = parent[current];
                } while (current != -1 && processed[current] == 1);
            } else {
                throw new Outcome(WA, "Answer contains cycle");
            }
        }
        int count = inf.nextInt();
        for (int i = 0; i < count; i++) {
            String word = inf.nextToken();
            boolean found = false;
            for (int j = 0; j < size; j++) {
                int current = j;
                found = true;
                for (int k = word.length() - 1; k >= 0; k--) {
                    if (label[current] != word.charAt(k)) {
                        found = false;
                        break;
                    }
                    current = parent[current];
                }
                if (found)
                    break;
            }
            if (!found)
                throw new Outcome(WA, String.format("'%s' is not found in dictionary", word));
        }
        int expectedSize = ans.nextInt();
        if (expectedSize < size)
            throw new Outcome(WA, String.format("Expected size %d, found %d", expectedSize, size));
        if (expectedSize > size)
            throw new Outcome(FAIL, String.format("Expected size %d, found %d", expectedSize, size));
        throw new Outcome(OK, String.format("%d", size));
    }
}
