import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;

public class Div1_526C {

	static int nV;

	static ArrayList<Integer>[] chldn;

	static int root;

	static int[][] anc;
	static int[] depth;

	static int[] num;

	static int[] nLoc;

	static int[][] tree;

	public static void main(String[] args) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter printer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
		nV = Integer.parseInt(reader.readLine());

		chldn = new ArrayList[nV];
		for (int i = 0; i < nV; i++) {
			chldn[i] = new ArrayList<>();
		}

		anc = new int[nV][21];
		depth = new int[nV];

		num = new int[nV];
		nLoc = new int[nV];
		tree = new int[nV * 4][2];
		for (int[] a : tree) {
			a[0] = a[1] = -1;
		}

		root = 0;

		StringTokenizer inputData = new StringTokenizer(reader.readLine());
		for (int i = 0; i < nV; i++) {
			num[i] = Integer.parseInt(inputData.nextToken());
			nLoc[num[i]] = i;
		}

		inputData = new StringTokenizer(reader.readLine());
		for (int i = 1; i < nV; i++) {
			anc[i][0] = Integer.parseInt(inputData.nextToken()) - 1;
			chldn[anc[i][0]].add(i);
		}

		preprocess();

		build(1, 0, nV - 1);

		int nQ = Integer.parseInt(reader.readLine());

		while (nQ-- > 0) {
			inputData = new StringTokenizer(reader.readLine());
			if (inputData.nextToken().equals("1")) {
				int a = Integer.parseInt(inputData.nextToken()) - 1;
				int b = Integer.parseInt(inputData.nextToken()) - 1;

				int temp = num[a];
				num[a] = num[b];
				num[b] = temp;

				nLoc[num[a]] = a;
				nLoc[num[b]] = b;

				update(1, 0, nV - 1, num[a]);
				update(1, 0, nV - 1, num[b]);
			} else {
				printer.println(query(1, 0, nV - 1, nLoc[0], nLoc[0]) + 1);
			}
		}
		printer.close();
	}

	static void build(int nI, int cL, int cR) {
		if (cL == cR) {
			tree[nI][0] = nLoc[cL];
			tree[nI][1] = nLoc[cL];
		} else {
			int mid = (cL + cR) >> 1;
			build(nI * 2, cL, mid);
			build(nI * 2 + 1, mid + 1, cR);
			if (tree[nI * 2][0] != -1 && tree[nI * 2 + 1][0] != -1) {
				merge(tree[nI * 2][0], tree[nI * 2][1], tree[nI * 2 + 1][0], tree[nI * 2 + 1][1]);
				tree[nI][0] = mResp[0];
				tree[nI][1] = mResp[1];
			}
		}
	}

	static int query(int nI, int cL, int cR, int e1, int e2) {
		if (cL == cR) {
			merge(e1, e2, nLoc[cL], nLoc[cL]);
			if (mResp[0] != -1) {
				return cL;
			} else {
				return cL - 1;
			}
		}
		int mid = (cL + cR) >> 1;

		merge(tree[nI * 2][0], tree[nI * 2][1], e1, e2);
		if (mResp[0] != -1) {
			return query(nI * 2 + 1, mid + 1, cR, mResp[0], mResp[1]);
		}
		return query(nI * 2, cL, mid, e1, e2);
	}

	static void update(int nI, int cL, int cR, int uI) {
		if (cL == cR) {
			tree[nI][0] = nLoc[cL];
			tree[nI][1] = nLoc[cL];
		} else {
			int mid = (cL + cR) >> 1;
			if (uI <= mid) {
				update(nI * 2, cL, mid, uI);
			} else {
				update(nI * 2 + 1, mid + 1, cR, uI);
			}
			merge(tree[nI * 2][0], tree[nI * 2][1], tree[nI * 2 + 1][0], tree[nI * 2 + 1][1]);
			tree[nI][0] = mResp[0];
			tree[nI][1] = mResp[1];
		}
	}

	static int[] mResp = new int[2];

	static void merge1(int... a) {
		for (int i = 0; i < 3; i++) {
			if (a[i] == -1) {
				mResp[0] = mResp[1] = -1;
				return;
			}
		}

		if (onPath(a[0], a[1], a[2])) {
			mResp[0] = a[0];
			mResp[1] = a[1];
			return;
		}
		if (onPath(a[0], a[2], a[1])) {
			mResp[0] = a[0];
			mResp[1] = a[2];
			return;
		}
		if (onPath(a[1], a[2], a[0])) {
			mResp[0] = a[1];
			mResp[1] = a[2];
			return;
		}
		mResp[0] = mResp[1] = -1;
	}

	static void merge(int... a) {
		merge1(a[0], a[1], a[2]);
		merge1(mResp[0], mResp[1], a[3]);
	}

	static boolean onPath(int a, int b, int c) {
		if (a == c || b == c) {
			return true;
		}

		if (depth[a] > depth[c]) {
			a = jump(a, depth[a] - depth[c] - 1);
		}
		if (depth[b] > depth[c]) {
			b = jump(b, depth[b] - depth[c] - 1);
		}
		if (a == b) {
			return false;
		}

		if (anc[a][0] == c || anc[b][0] == c) {
			return true;
		}

		return false;
	}

	// good for depth of up to 1_048_576 = 2^20

	static void preprocess() {
		anc[root][0] = root;
		fParent(root);

		for (int k = 1; k <= 20; k++) {
			for (int i = 0; i < nV; i++) {
				anc[i][k] = anc[anc[i][k - 1]][k - 1];
			}
		}
	}

	static void fParent(int cV) {
		for (int aV : chldn[cV]) {
			anc[aV][0] = cV;
			depth[aV] = depth[cV] + 1;
			fParent(aV);
		}
	}

	static int fLCA(int a, int b) {
		if (depth[a] > depth[b]) {
			int temp = b;
			b = a;
			a = temp;
		}
		b = jump(b, depth[b] - depth[a]);
		if (a == b) {
			return a;
		}
		for (int i = 20; i >= 0; i--) {
			if (anc[a][i] != anc[b][i]) {
				a = anc[a][i];
				b = anc[b][i];
			}
		}
		return anc[a][0];
	}

	static int jump(int cV, int d) {
		for (int i = 0; i <= 20; i++) {
			if ((d & (1 << i)) != 0) {
				cV = anc[cV][i];
			}
		}
		return cV;
	}

	static Comparator<Integer> BY_DEPTH = new Comparator<Integer>() {
		public int compare(Integer o1, Integer o2) {
			return -Integer.compare(depth[o1], depth[o2]); // greatest depth first
		}
	};
}