
import java.io.*;
import java.util.*;

public class FearOfTheDark implements Runnable {

	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
	static StringTokenizer st = new StringTokenizer("");

	public static String next() {
		try	{
		while (!st.hasMoreTokens()) {
			String s = br.readLine();
			if (s == null)
				return null;
			st = new StringTokenizer(s);
		}
		return st.nextToken();
		}	catch(Exception e)	{
			return	null;
		}
	}
	public static void main(String[] asda) throws Exception {
		new Thread(null, new FearOfTheDark(), "Main", 1<<28).run();
	}
	public void run() {
		int N = Integer.parseInt( next() );
		ArrayList<Integer> [] g = new ArrayList [N];
		for (int k = 0; k < N; k++)	g[k] = new ArrayList<Integer>();
		for (int k = 1; k < N; k++)	{
			int a = Integer.parseInt( next() ) - 1;
			int b = Integer.parseInt( next() ) - 1;

			g[a].add(b);
			g[b].add(a);
		}

		HLD h = new HLD(g);
	//	h.print(out);

		int M = Integer.parseInt( next() );
		while	(M-- > 0)	{
			int q = Integer.parseInt( next() );
			int a = Integer.parseInt( next() ) - 1;
			int b = Integer.parseInt( next() ) - 1;

			if (q == 2) {
				out.println( h.query(a, b) );
			}	else	{
				h.update(a, b);
			}
		}
        //
        out.flush();
        System.exit(0);
    }
	
}

class HLD {
	private int root;
	private List<Integer> [] g;

	LCA lca;
	LazyBinarySegmentTree stree;

	HLD(List<Integer> [] g)	{
		this.g = g;
		int N = g.length;

		size = new int [N];
		parent = new int [N];
		root = 0;
		dfs(root, -1);

		numberOfChains = currentIndex = 0;
		chains = new LinkedList [N];
		chainHead = new int [N];
		chainIndex = new int [N];
		nodeIndex = new int [N];
		decompose(root);

		lca = new LCA(g, root);
		stree = new LazyBinarySegmentTree(N);
	}

	public void update(int a, int b)	{
		int ancestor = lca.getLCA(a, b);

		mupdate(ancestor, a);
	//	System.out.println("...");

		mupdate(ancestor, b);
	//	System.out.println();

		stree.flip( nodeIndex[ancestor], nodeIndex[ancestor] );
	}

	private void mupdate(int ancestor, int node)	{
		while	( chainIndex[ancestor] != chainIndex[node] )	{
			int head = chains[ chainIndex[node] ].get(0);

	//		System.out.printf("updating(%d, %d)\n", nodeIndex[head], nodeIndex[node] );
			stree.flip(nodeIndex[head], nodeIndex[node]);
			node = parent[node];
		}

	//	System.out.printf("updating(%d, %d)\n", nodeIndex[ancestor], nodeIndex[node] );
		stree.flip( nodeIndex[ancestor], nodeIndex[node] );
	}

	public int query(int a, int b)	{
		int ancestor = lca.getLCA(a, b);

		int ans = internalQuery(ancestor, a);
	//	System.out.println("...");

		ans += internalQuery(ancestor, b);
	//	System.out.println();

		ans += stree.getFlipped( nodeIndex[ancestor], nodeIndex[ancestor] );

		return ans;
	}

	private int internalQuery(int ancestor, int node)	{
		int ans = 0;
		while	( chainIndex[ancestor] != chainIndex[node] )	{
			int head = chains[ chainIndex[node] ].get(0);

		//	System.out.printf("query(%d, %d)\n", nodeIndex[head], nodeIndex[node] );
			ans += stree.getFlipped(nodeIndex[head], nodeIndex[node]);
			node = parent[node];
		}

	//	System.out.printf("query(%d, %d)\n", nodeIndex[ancestor], nodeIndex[node] );
		ans += stree.getFlipped( nodeIndex[ancestor], nodeIndex[node] );
		return	ans;
	}

	public void print(PrintWriter out)	{
		out.println("size: " + Arrays.toString(size) );
		out.println("chains:");
		for (int k = 0; k <= numberOfChains; k++)
			out.println(" " + k + ": " + chains[k] );

		out.println("chainIndex: " + Arrays.toString(chainIndex));
		out.println("nodeIndex: " + Arrays.toString(nodeIndex));
	}

	private int numberOfChains;
	private int currentIndex;
	private List<Integer> [] chains;	// chains[k] = the list of nodes in the chain k
	private int [] chainHead;			// chainHead[k] = the head note at chain k
	private int [] chainIndex;			// chainindex[k] = the chain index where node k belongs
	private int [] nodeIndex;			// nodeindex[k] = the index assigned to node k after decomposition

	// apply decomposition to a node
	private void decompose(int node)	{
		if (chains[numberOfChains] == null) {
			// this is a new chain
			chains[numberOfChains] = new LinkedList<Integer>();
			chainHead[numberOfChains] = node;
		}
		chains[numberOfChains].add(node);
		chainIndex[node] = numberOfChains;
		nodeIndex[node] = currentIndex++;

	//	System.out.println("decompose " + node);
		// find the heaviest child
		int heavyChild = -1;
		for (int to : g[node])	if (to != parent[node]) {
			if ( heavyChild == -1 || size[heavyChild] < size[to] ) {
				heavyChild = to;
			}
		}

	//	System.out.println(" heavy child " + heavyChild);

		if (heavyChild == -1) {
			return;	// this node is a leaf
		}

		decompose(heavyChild);

		for (int to : g[node])	if (to != parent[node] && to != heavyChild) {
			// decompose this child into a new chain
			numberOfChains++;
			decompose(to);
		}
	}

	private int [] size;	// size[k] = size of the subtree rooted at k
	private int [] parent;	// parent[k] = parent of node k
	private void dfs(int node, int dad)	{
		parent[node] = dad;
		size[node] = 1;
		for (int to : g[node])	if (dad != to) {
			dfs(to, node);
			size[node] += size[to];
		}
	}
}

class LazyBinarySegmentTree {
	int [] ones, twos, flip;
	int size;
	
	
	public LazyBinarySegmentTree(int size) {
		size++;
		int N = 1;
		while ( (N <<= 1) < size);
		N <<= 1;

		ones = new int[N];
		twos = new int[N];
		flip = new int[N];
		
		this.size = size;
	}
	// x and y sould start in 1
	void flip(int x, int y)	{
		x++; y++;
		update( 1, size, x, y, 1 );
	//	System.out.printf("update(%d, %d)\n", x, y );
	}
	
	int getFlipped(int x, int y)	{
		x++; y++;
		// lasta parameter is for the initial status of each element in array (0, 1)
	//	System.out.printf("query(%d, %d) = %d\n", x, y, query( 1, size, x, y, 1, 1 ) );
		return	query( 1, size, x, y, 1, 1 );
	}
	
	
	private void update(int lo, int hi, int x, int y, int i) {
		if (x > hi || y < lo)
			return;
		
		int mid;
		if (x <= lo && y >= hi) {
			ones[i] = (hi - lo + 1) - ones[i];
			flip[i] += 1;
			if (flip[i] > 1)
				flip[i] -= 2;
			return;
		}
		
		mid = (lo + hi) >> 1;
		update(lo, mid, x, y, 2 * i);
		update(mid + 1, hi, x, y, 2 * i + 1);
		
		ones[i] = ones[2 * i] + ones[2 * i + 1];
	
		if (flip[i] == 1) {
			ones[i] = (hi - lo + 1) - ones[i];
		}
	}
	

	private int query(int lo, int hi, int x, int y, int i, int flag) {
		if (x > hi || y < lo)
			return 0;
		
		if (x <= lo && y >= hi) {
			if (flag == 1)
				return ones[i];
			
			return (hi - lo + 1) - ones[i];
		}
		
		
		int mid = (lo + hi) >> 1, nflag = (flag + flip[i]);
		
		if (nflag > 1)
			nflag -= 2;
		
		return	query(lo, mid, x, y, 2 * i, nflag)	+
				query(mid + 1, hi, x, y, 2 * i + 1, nflag);
	}
	
}


class LCA {
	int N;
	int logN;
	int[] dep;
	int[][] go;
	List<Integer>[] g;
	// 1 based index
	LCA(List<Integer> g[], int root) {
		this.g = g;
		N = g.length;
		logN = 1;
		while ((1 << logN) <= N)
			logN++;

	//	System.out.println(N + " " + logN);
		dep = new int[N];
		go = new int[N][logN];

		dfs(root, 0, 0);

		// Prepare for LCA queries.
		for (int k = 1; k < logN; ++k) {
			for (int i = 1; i < N; ++i) {
				go[i][k] = go[go[i][k - 1]][k - 1];
			}
		}
	}

	private void dfs(int id, int depth, int dad) {
		go[id][0] = dad;
		dep[id] = depth;

		for (int to : g[id]) {
			if ( to != dad )
				dfs(to, depth + 1, id);
		}
	}

	int getLCA(int u, int v) {
		if (dep[u] < dep[v]) {
			int aux = u;
			u = v;
			v = aux;
		}

		int diff = dep[u] - dep[v];
		for (int i = 0; diff != 0; ++i, diff >>= 1) {
			if ( (diff & 1) != 0 ) {
				u = go[u][i];
			}
		}

		if (u == v)
			return u;

		for (int i = logN - 1; i >= 0; --i) {
			if (go[u][i] != go[v][i]) {
				u = go[u][i];
				v = go[v][i];
			}
		}
		return go[u][0];
	}
}


