// Arup Guha
// 11/25/2013
// Solution to 2013 Pacific Northwest Regional Problem K: Klingons

import java.util.*;

public class k {

	public static node[] tree1;
	public static node[] tree2;
	public static HashSet<Integer> equalTrees;
	public static HashSet<Integer> notEqualTrees;

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);
		int numCases = stdin.nextInt();

		// Go through each case.
		for (int loop=0; loop<numCases; loop++) {

			int N = stdin.nextInt();
			int M = stdin.nextInt();

			equalTrees = new HashSet<Integer>();
			notEqualTrees = new HashSet<Integer>();

			// Read in the first tree.
			tree1 = new node[N];
			for (int i=0; i<N; i++) {
				String s = stdin.next();
				int parent = stdin.nextInt();
				tree1[i] = new node(s.charAt(0), i);
				if (i > 0) tree1[parent].children.add(tree1[i]);
			}
			tree1[0].setSize();

			// Read in the second tree.
			tree2 = new node[M];
			for (int i=0; i<M; i++) {
				String s = stdin.next();
				int parent = stdin.nextInt();
				tree2[i] = new node(s.charAt(0), i);
				if (i > 0) tree2[parent].children.add(tree2[i]);
			}
			tree2[0].setSize();

			// Output answer.
			System.out.println(solve());
		}
	}

	public static int solve() {

		// Sort by subtree size so we can do a sweep.
		Arrays.sort(tree1);
		Arrays.sort(tree2);

		// Start from the largest nodes.
		int i = 0, j = 0;
		while (i < tree1.length && j < tree2.length) {

			// We can advance one pointer or the other.
			if (tree1[i].size > tree2[j].size) i++;
			else if (tree1[i].size < tree2[j].size) j++;

			// Equal size case.
			else {

				// Set markers for next unique tree size.
				int nexti = i;
				while (nexti < tree1.length && tree1[nexti].size == tree1[i].size) nexti++;
				int nextj = j;
				while (nextj < tree2.length && tree2[nextj].size == tree2[j].size) nextj++;

				// Just run brute force on all trees of the same size.
				for (int a=i; a<nexti; a++) {
					for (int b=j; b<nextj; b++) {
						if (equal(tree1[a], tree2[b]))
							return tree1[a].size;
					}
				}

				// Advance to the next smaller size of tree in both trees.
				i = nexti;
				j = nextj;
			}
		}

		// Never found a match...
		return 0;
	}

	// Returns true iff nodes n1 and n2 head equal clans.
	public static boolean equal(node n1, node n2) {

		// IDs of our nodes, used for HashSet lookups.
		int i1 = n1.ID;
		int i2 = n2.ID;

		// We know the answer already...
		if (equalTrees.contains(10000*i1+i2)) return true;
		if (notEqualTrees.contains(10000*i1+i2)) return false;

		// Base cases.
		if (n1.size != n2.size || n1.style != n2.style || n1.children.size() != n2.children.size()) {
			notEqualTrees.add(10000*i1+i2);
			return false;
		}

		// If subordinate clans don't match, this isn't a match.
		for (int i=0; i<n1.children.size(); i++) {
			if (!equal(n1.children.get(i), n2.children.get(i))) {
				notEqualTrees.add(10000*i1+i2);
				return false;
			}
		}

		// If we get here, we're equal!
		equalTrees.add(10000*i1+i2);
		return true;
	}
}

class node implements Comparable<node> {

	public int style;
	public int ID;
	public ArrayList<node> children;
	public int size;

	public node(char c, int i) {
		style = c - 'A';
		children = new ArrayList<node>();
		ID = i;
	}

	// Set the size of this node (and everything below it)...
	public int setSize() {
		int cnt = 1;
		for (int i=0; i<children.size(); i++)
			cnt += children.get(i).setSize();

		size = cnt;
		return cnt;
	}

	public int compareTo(node other) {
		if (this.size != other.size)
			return other.size - this.size;
		return this.ID - other.ID;
	}
}