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>
#pragma GCC optimize("Ofast")
using namespace std;
struct node {
  long long val, ind;
};
node segment_tree[800001 * 4];
int log2(int x) { return sizeof(x) * 8 - __builtin_clz(x) - 1; }
int reserved, n;
node neutro = {0, 0};
node op(node u, node v) {
  if (u.val > v.val) return {u.val, u.ind};
  return {v.val, v.ind};
}
node query_(int p, int q, int l, int r, int index) {
  if (p == l && q == r) return segment_tree[index];
  if (q <= (r + l) / 2)
    return query_(p, q, l, (r + l) / 2, 2 * index + 1);
  else if (p > (r + l) / 2)
    return query_(p, q, 1 + (r + l) / 2, r, 2 * index + 2);
  else
    return op(query_(p, (r + l) / 2, l, (r + l) / 2, 2 * index + 1),
              query_(1 + (r + l) / 2, q, 1 + (r + l) / 2, r, index * 2 + 2));
}
node query(int p, int q) { return query_(p, q, 0, reserved, 0); }
void update(int index, node value) {
  index += reserved;
  segment_tree[index] = value;
  index = (index - 1) / 2;
  while (index) {
    segment_tree[index] =
        op(segment_tree[index * 2 + 1], segment_tree[index * 2 + 2]);
    index = (index - 1) / 2;
  }
  if (reserved)
    segment_tree[index] =
        op(segment_tree[index * 2 + 1], segment_tree[index * 2 + 2]);
}
void build_segment_tree(vector<node> &arr) {
  int n = (int)arr.size();
  int e = log2(n);
  if (__builtin_popcount(n) != 1) e++;
  reserved = 1 << e;
  reserved--;
  for (int i = reserved; i < 2 * reserved + 1; i++) {
    if (i - reserved < n) {
      segment_tree[i] = arr[i - reserved];
    } else
      segment_tree[i] = neutro;
  }
  for (int k = reserved - 1; k >= 0; k--) {
    segment_tree[k] = op(segment_tree[2 * k + 1], segment_tree[2 * k + 2]);
  }
}
int cp[400010];
int find(int x) { return cp[x] = cp[x] == x ? x : find(cp[x]); }
void union_(int x, int y) { cp[find(x)] = find(y); }
vector<pair<int, int> > edg, queries;
vector<int> col, par, opn, cl;
vector<vector<int> > g;
vector<int> vis;
vector<node> A;
int cnt = 0;
void dfs(int u) {
  vis[u] = 1;
  opn[u] = cnt++;
  A.push_back({col[u], u});
  for (int v : g[u]) {
    if (!vis[v]) dfs(v);
  }
  cl[u] = cnt++;
  A.push_back({col[u], u});
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  par.assign(2 * n, -1);
  opn.assign(2 * n, -1);
  cl.assign(2 * n, -1);
  vis.assign(2 * n, 0);
  g.assign(2 * n, vector<int>());
  for (int i = 0; i < 2 * n; ++i) cp[i] = i;
  for (int j = 0; j < n; ++j) {
    int aux;
    cin >> aux;
    col.push_back(aux);
  }
  col.resize(2 * n, 0);
  for (int k = 0; k < m; ++k) {
    int u, v;
    cin >> u >> v;
    edg.push_back({u - 1, v - 1});
  }
  vector<int> visq(m, 0);
  for (int l = 0; l < q; ++l) {
    int t, u;
    cin >> t >> u;
    if (t == 2) visq[u - 1] = 1;
    queries.push_back({t, u - 1});
  }
  for (int i1 = 0; i1 < m; ++i1) {
    if (!visq[i1]) queries.push_back({2, i1});
  }
  vector<int> root(queries.size(), -1);
  for (int i = queries.size() - 1; i >= 0; i--) {
    int t = queries[i].first, u = queries[i].second;
    if (t == 1)
      root[i] = find(u);
    else {
      int v = edg[u].second;
      u = edg[u].first;
      if (find(u) == find(v)) continue;
      par[find(u)] = par[find(v)] = n;
      g[find(u)].push_back(n);
      g[find(v)].push_back(n);
      g[n].push_back(find(u));
      g[n].push_back(find(v));
      union_(u, n);
      union_(v, n);
      n++;
    }
  }
  for (int i = 0; i < n; ++i) {
    if (!vis[find(i)]) dfs(find(i));
  }
  build_segment_tree(A);
  for (int i = 0; i < queries.size(); ++i) {
    int t = queries[i].first, j = queries[i].second;
    if (t == 2) continue;
    int u = root[i];
    node res = query(opn[u], cl[u]);
    cout << res.val << "\n";
    if (res.val) {
      update(opn[res.ind], neutro);
      update(cl[res.ind], neutro);
    }
  }
}
