import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; public class Main { static int[] c; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] sa = br.readLine().split(" "); int n = Integer.parseInt(sa[0]); int k = Integer.parseInt(sa[1]); int q = Integer.parseInt(sa[2]); sa = br.readLine().split(" "); c = new int[n]; for (int i = 0; i < n; i++) { c[i] = Integer.parseInt(sa[i]); } sa = br.readLine().split(" "); int[] a = new int[k]; for (int i = 0; i < k; i++) { a[i] = Integer.parseInt(sa[i]) - 1; } List> list = new ArrayList<>(n); for (int i = 0; i < n; i++) { list.add(new ArrayList<>()); } for (int i = 0; i < n - 1; i++) { sa = br.readLine().split(" "); int e = Integer.parseInt(sa[0]) - 1; int f = Integer.parseInt(sa[1]) - 1; list.get(e).add(f); list.get(f).add(e); } SegTreeLCA lca = new SegTreeLCA(n, list, 0); SegTree st = new SegTree(k, -1, (o1, o2) -> { if (o1 == -1) return o2; if (o2 == -1) return o1; return lca.lca(o1, o2).i; }); for (int i = 0; i < k; i++) { st.update(i, a[i]); } PrintWriter pw = new PrintWriter(System.out); for (int i = 0; i < q; i++) { sa = br.readLine().split(" "); if (sa[0].equals("1")) { int x = Integer.parseInt(sa[1]) - 1; int y = Integer.parseInt(sa[2]) - 1; st.update(x, y); } else { int l = Integer.parseInt(sa[1]) - 1; int r = Integer.parseInt(sa[2]); pw.println(lca.get(st.query(l, r)).c); } } pw.flush(); br.close(); } static class SegTreeLCA { int n = 2; int n2, idx; Obj[] arr; int[] first; Obj INF = new Obj(-1, Integer.MAX_VALUE, 0); /** * 初期化 * @param size 頂点数 * @param list 隣接リスト * @param root 根の頂点番号 */ public SegTreeLCA(int size, List> list, int root) { while (n < size) { n <<= 1; } n <<= 1; n2 = n * 2 - 1; idx = n - 1; arr = new Obj[n2]; first = new int[size]; Arrays.fill(first, -1); Obj r = new Obj(root, 0, c[root]); arr[idx] = r; first[root] = idx - n + 1; idx++; dfs(list, r, -1); for (int i = idx; i < n2; i++) { arr[i] = INF; } for (int i = n - 2; i >= 0; i--) { if (arr[i * 2 + 1].dep < arr[i * 2 + 2].dep) { arr[i] = arr[i * 2 + 1]; } else { arr[i] = arr[i * 2 + 2]; } } } private void dfs(List> list, Obj cur, int p) { for (int ch : list.get(cur.i)) { if (ch != p) { int cmax = Math.max(cur.c, c[ch]); Obj o = new Obj(ch, cur.dep + 1, cmax); arr[idx] = o; if (first[ch] == -1) { first[ch] = idx - n + 1; } idx++; dfs(list, o, cur.i); arr[idx] = cur; idx++; } } } /** * 頂点Iのオブジェクト取得(0≦I<size) */ public Obj get(int i) { return arr[first[i] + n - 1]; } /** * 頂点A,BのLCA取得(0≦A,B<size) */ public Obj lca(int a, int b) { int l = Math.min(first[a], first[b]); int r = Math.max(first[a], first[b]); return query(l, r + 1, 0, 0, n); } private Obj query(int l, int r, int k, int beg, int end) { if (end <= l || r <= beg) return INF; // 交差しない if (l <= beg && end <= r) return arr[k]; // 完全に含む Obj o1 = query(l, r, k * 2 + 1, beg, (beg + end) / 2); Obj o2 = query(l, r, k * 2 + 2, (beg + end) / 2, end); if (o1.dep < o2.dep) { return o1; } return o2; } private static class Obj { int i, dep, c; public Obj(int i, int dep, int c) { this.i = i; this.dep = dep; this.c = c; } } } static class SegTree { // 親へのアクセス:(n - 1) / 2 // 子へのアクセス:n * 2 + 1、n * 2 + 2 int n = 2; // 要素(葉)の数 int n2; // 全ノード数 T NA; List list; BiFunction func; /** * 初期化 O(N) * @param num 要素(葉)の数 * @param na 無効とみなせる値 * @param func 区間に対する操作が可能な関数(戻り値は新規オブジェクト) */ public SegTree(int num, T na, BiFunction func) { while (n < num) n <<= 1; n2 = n * 2 - 1; NA = na; list = new ArrayList(n2); for (int i = 0; i < n2; i++) list.add(NA); this.func = func; } /** * 更新 O(logN) * @param i インデックス(0~n-1) * @param x 更新値 */ void update(int i, T x) { i += n - 1; // arr上でのインデックス list.set(i, x); while (i > 0) { i = (i - 1) / 2; list.set(i, func.apply(list.get(i * 2 + 1), list.get(i * 2 + 2))); } } /** * 取得 O(logN) * インデックスl以上r未満の区間の値 */ T query(int l, int r) { return query(l, r, 0, 0, n); } /** * 取得 O(logN) * インデックスl以上r未満の区間の値、beg, endにはノードkに対応する区間 * query(l, r, 0, 0, n); */ private T query(int l, int r, int k, int beg, int end) { if (end <= l || r <= beg) return NA; // 交差しない if (l <= beg && end <= r) return list.get(k); // 完全に含む T v1 = query(l, r, k * 2 + 1, beg, (beg + end) / 2); T v2 = query(l, r, k * 2 + 2, (beg + end) / 2, end); return func.apply(v1, v2); } } }