9 5 14
7 1 4 8 5 2 6 9 3
2 8
1 6
5 7
1 3
3 9
1 5
1 8
1 5
1 4
1 8
1 3
1 5
1 5
1 7
1 7
2 3
1 2
1 1
1 2
 6 5 8
1 2 6 3 4 5
2 4
1 3
1 6
3 5
2 5
1 1
1 4
1 1
2 1
2 5
2 2
2 3
1 4
 2 1 3
1 2
1 2
1 1
1 1
1 1

6
9
5
8
1
7
0
0
0
0
0
4
0
 6
5
4
3
 2
1
0

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXM = 3e5 + 5;
const int MAXQ = 5e5 + 5;
const int inf = 0x3f3f3f3f;
struct Segment_Tree {
  int n;
  vector<pair<int, int> > mx;
  inline void push_up(int u) {
    mx[u] = max(mx[((u) << 1)], mx[((u) << 1 | 1)]);
  }
  void build(vector<int> &val) {
    n = (int)val.size() - 1;
    mx.resize((n + 1) << 2);
    build(1, 0, n, val);
  }
  void build(int u, int l, int r, vector<int> &val) {
    if (l == r) {
      mx[u] = make_pair(val[l], l);
      return;
    }
    int mid = (l + r) >> 1;
    build(((u) << 1), l, mid, val);
    build(((u) << 1 | 1), mid + 1, r, val);
    push_up(u);
  }
  pair<int, int> query(int ql, int qr) { return query(1, 0, n, ql, qr); }
  pair<int, int> query(int u, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr) return mx[u];
    int mid = (l + r) >> 1;
    pair<int, int> res = make_pair(-inf, -1);
    if (ql <= mid) res = max(res, query(((u) << 1), l, mid, ql, qr));
    if (mid < qr) res = max(res, query(((u) << 1 | 1), mid + 1, r, ql, qr));
    return res;
  }
  void update(int q, int k) { update(1, 0, n, q, k); }
  void update(int u, int l, int r, int q, int k) {
    if (l == r) {
      mx[u].first = k;
      return;
    }
    int mid = (l + r) >> 1;
    if (q <= mid)
      update(((u) << 1), l, mid, q, k);
    else
      update(((u) << 1 | 1), mid + 1, r, q, k);
    push_up(u);
  }
};
struct Edge_uv {
  int u, v;
};
struct Oper {
  int type, x;
};
int fa[MAXN], size[MAXN];
vector<int> nodes[MAXN];
inline void init(int n) {
  for (int i = 1; i <= n; ++i) fa[i] = i, size[i] = 1, nodes[i].push_back(i);
}
int find(int u) { return fa[u] == u ? u : find(fa[u]); }
inline int connect(int u, int v) {
  int fu = find(u), fv = find(v);
  if (fu == fv) return 0;
  if (size[fu] < size[fv]) swap(u, v), swap(fu, fv);
  fa[fv] = fu;
  size[fu] += size[fv];
  for (int i = 0; i < (int)nodes[fv].size(); ++i)
    nodes[fu].push_back(nodes[fv][i]);
  nodes[fv].clear();
  return fv;
}
int p[MAXN];
Edge_uv e[MAXM];
Oper op[MAXQ];
int main(void) {
  int n, m, Q;
  scanf("%d%d%d", &n, &m, &Q);
  for (int i = 1; i <= n; ++i) scanf("%d", &p[i]);
  for (int i = 1; i <= m; ++i) scanf("%d%d", &e[i].u, &e[i].v);
  static bool del[MAXM];
  for (int i = 1; i <= Q; ++i) {
    int type, x;
    scanf("%d%d", &type, &x);
    op[i] = (Oper){type, x};
    if (type == 2) del[x] = 1;
  }
  init(n);
  static int son[MAXM];
  for (int i = 1; i <= m; ++i)
    if (!del[i]) son[i] = connect(e[i].u, e[i].v);
  for (int i = Q; i >= 1; --i)
    if (op[i].type == 2) {
      int x = op[i].x;
      son[x] = connect(e[i].u, e[i].v);
    }
  static int att[MAXN], pos[MAXN];
  static Segment_Tree tree[MAXN];
  for (int u = 1; u <= n; ++u)
    if (fa[u] == u) {
      vector<int> val;
      for (int i = 0; i < (int)nodes[u].size(); ++i) {
        int v = nodes[u][i];
        att[v] = u;
        pos[v] = i;
        val.push_back(p[v]);
      }
      tree[u].build(val);
    }
  for (int i = 1; i <= Q; ++i) {
    int type = op[i].type, x = op[i].x;
    if (type == 1) {
      int ff = find(x), at = att[x];
      int l = pos[ff], r = pos[ff] + size[ff] - 1;
      pair<int, int> res = tree[at].query(l, r);
      printf("%d\n", res.first);
      tree[at].update(res.second, 0);
    } else {
      if (son[x] == 0) continue;
      int v = son[x], tmp = size[v];
      while (fa[v] != v) size[fa[v]] -= tmp, v = fa[v];
      fa[son[x]] = son[x];
    }
  }
  return 0;
}
