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 M = 1000000007;
const int MM = 998244353;
const long double PI = acos(-1);
int power(int b, int e, int m) {
  if (e == 0) return 1;
  if (e & 1) return b * power(b * b % m, e / 2, m) % m;
  return power(b * b % m, e / 2, m);
}
int power(int b, int e) {
  if (e == 0) return 1;
  if (e & 1) return b * power(b * b, e / 2);
  return power(b * b, e / 2);
}
template <typename T, typename U>
static inline void amin(T &x, U y) {
  if (y < x) x = y;
}
template <typename T, typename U>
static inline void amax(T &x, U y) {
  if (x < y) x = y;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << '(' << p.first << "," << p.second << ')';
}
const int N = 200005;
const int LOGN = 19;
int val[N];
struct node {
  int mx, idx;
} fake{-N, -1};
struct SEGTREE {
  int a[N];
  SEGTREE() { memset(a, 0, sizeof(a)); }
  node tree[4 * N];
  int lazy[4 * N];
  inline node combine(node a, node b) {
    node ret;
    ret.mx = max(a.mx, b.mx);
    if (ret.mx == a.mx)
      ret.idx = a.idx;
    else
      ret.idx = b.idx;
    return ret;
  }
  inline node make_node(int val, int st) {
    node ret;
    ret.mx = val;
    ret.idx = st;
    return ret;
  }
  void buildTree(int v, int st, int en) {
    if (st == en) {
      tree[v] = make_node(a[st], st);
      return;
    }
    int mid = (st + en) >> 1;
    buildTree(v << 1, st, mid);
    buildTree(v << 1 | 1, mid + 1, en);
    tree[v] = combine(tree[v << 1], tree[v << 1 | 1]);
  }
  void update(int v, int st, int en, int in, int val) {
    int mid = (st + en) >> 1;
    if (st == en) {
      tree[v] = make_node(val, st);
      a[st] = val;
      return;
    }
    if (in <= mid)
      update(v << 1, st, mid, in, val);
    else
      update(v << 1 | 1, mid + 1, en, in, val);
    tree[v] = combine(tree[v << 1], tree[v << 1 | 1]);
  }
  node query(int v, int st, int en, int l, int r) {
    if (en < l || st > r) return fake;
    if (st >= l && en <= r) return tree[v];
    int mid = (st + en) >> 1;
    return combine(query(v << 1, st, mid, l, r),
                   query(v << 1 | 1, mid + 1, en, l, r));
  }
} seg;
struct dsu_tree {
  vector<int> pos, idx, par, rnk, par_node;
  int cur = 0, indexing = 0;
  int root = -1;
  struct dsu_node {
    int l, r, L, R, v;
    int p[LOGN];
    int w;
    dsu_node() : L(-1), R(-1), w(0), v(-1), l(-1), r(-1) {}
  };
  vector<dsu_node> tr;
  dsu_tree(int n) : cur(0), indexing(0), root(-1) {
    pos.resize(n + 1);
    idx.resize(n + 1);
    par_node.resize(n + 1);
    par.resize(n + 1);
    tr.resize(2 * n + 2);
    rnk.resize(n + 1);
    for (int i = 0; i <= n; ++i) rnk[i] = 0, par[i] = i;
    for (int i = 1; i <= n; ++i) {
      int x = getNode();
      tr[x].v = i;
      assert(x == i - 1);
      par_node[i] = x;
    }
  }
  int parent(int i) { return par[i] = (par[i] == i) ? i : parent(par[i]); }
  int getNode() {
    int v = cur++;
    tr[v] = dsu_node();
    return v;
  }
  void merge(int x, int y, int w) {
    x = parent(x), y = parent(y);
    if (x == y) return;
    int u = getNode();
    tr[u].w = w;
    tr[u].L = par_node[x];
    tr[u].R = par_node[y];
    if (rnk[x] > rnk[y])
      par[y] = x, par_node[x] = u;
    else
      par[x] = y, par_node[y] = u;
    if (rnk[x] == rnk[y]) ++rnk[y];
  }
  void dfs(int s) {
    for (int j = 1; j < LOGN; ++j) tr[s].p[j] = tr[tr[s].p[j - 1]].p[j - 1];
    if (tr[s].v != -1) {
      idx[tr[s].v] = indexing;
      pos[indexing] = tr[s].v;
      tr[s].l = tr[s].r = indexing;
      ++indexing;
    }
    if (tr[s].L != -1) {
      tr[tr[s].L].p[0] = s;
      tr[tr[s].R].p[0] = s;
      dfs(tr[s].L);
      dfs(tr[s].R);
      tr[s].l = tr[tr[s].L].l;
      tr[s].r = tr[tr[s].R].r;
    }
  }
  void dfs() {
    root = cur - 1;
    tr[root].p[0] = root;
    dfs(root);
  }
  pair<int, int> lift(int u, int w) {
    u = u - 1;
    for (int j = LOGN - 1; j >= 0; --j) {
      if (tr[tr[u].p[j]].w >= w) u = tr[u].p[j];
    }
    return make_pair(tr[u].l, tr[u].r);
  }
};
int _runtimeTerror_() {
  int n, m, q;
  cin >> n >> m >> q;
  for (int i = 1; i <= n; ++i) cin >> val[i];
  vector<pair<int, int>> query, edges(m);
  vector<int> mark(m, 10 * N), in(m);
  for (int i = 0; i < m; ++i) {
    in[i] = i;
    cin >> edges[i].first >> edges[i].second;
  }
  for (int i = 0; i < q; ++i) {
    int tt, u;
    cin >> tt >> u;
    query.push_back({tt, u});
    if (tt == 2) mark[u - 1] = i;
  }
  sort(in.begin(), in.end(), [&](int x, int y) { return mark[x] > mark[y]; });
  dsu_tree dsu(n);
  for (auto &j : in) {
    dsu.merge(edges[j].first, edges[j].second, mark[j]);
  }
  vector<bool> vis(n + 1, false);
  for (int i = 1; i <= n; ++i) {
    int x = dsu.parent(i);
    if (vis[x]) continue;
    vis[x] = true;
    int root = dsu.par_node[x];
    dsu.tr[root].p[0] = root;
    dsu.dfs(root);
  }
  for (int i = 1; i <= n; ++i) seg.a[dsu.idx[i]] = val[i];
  seg.buildTree(1, 0, n - 1);
  for (int i = 0; i < q; ++i) {
    if (query[i].first == 2) continue;
    pair<int, int> range = dsu.lift(query[i].second, i);
    node u = seg.query(1, 0, n - 1, range.first, range.second);
    cout << u.mx << "\n";
    seg.update(1, 0, n - 1, u.idx, 0);
  }
  return 0;
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int TESTS = 1;
  while (TESTS--) _runtimeTerror_();
  return 0;
}
