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;
struct dsu {
  vector<int> id;
  vector<int> last;
  dsu(int n) {
    id = vector<int>(n);
    iota(id.begin(), id.end(), 0);
    last = vector<int>(n);
    iota(last.begin(), last.end(), 0);
  }
  int find(int a) {
    while (id[a] != a) {
      id[a] = id[id[a]];
      a = id[a];
    }
    return a;
  }
  bool unite(int a, int b) {
    a = find(a);
    b = find(b);
    if (a == b) return false;
    last[a] = last[b];
    id[b] = a;
    return true;
  }
};
class segtree {
 private:
  struct node {
    int mx = 0;
    int mx_ind = -1;
    void assign(int ind, int v) {
      mx = v;
      mx_ind = ind;
    }
    void merge(node &a, node &b) {
      if (a.mx >= b.mx) {
        mx_ind = a.mx_ind;
      } else {
        mx_ind = b.mx_ind;
      }
      mx = max(a.mx, b.mx);
    }
  };
  int b;
  node *tree;

 public:
  const int n;
  segtree(int _n) : n(_n) {
    assert(_n > 0);
    for (b = 1; b < n; b <<= 1)
      ;
    tree = new node[b << 1];
  }
  template <typename... M>
  void update(int ind, const M &...v) {
    tree[b + ind].assign(ind, v...);
    for (int i = (b + ind) / 2; i > 0; i >>= 1) {
      tree[i].merge(tree[i * 2], tree[i * 2 + 1]);
    }
  }
  node get(int l, int r) const {
    assert(0 <= l && l <= r && r < n);
    l += b;
    r += b;
    if (l == r) {
      return tree[l];
    }
    node left = tree[l];
    node right = tree[r];
    while (l + 1 < r) {
      if (l % 2 == 0) {
        left.merge(left, tree[l + 1]);
      }
      if (r % 2) {
        right.merge(tree[r - 1], right);
      }
      l /= 2;
      r /= 2;
    }
    node answer;
    answer.merge(left, right);
    return answer;
  }
};
void foo() {
  int n, m, q;
  cin >> n >> m >> q;
  vector<int> p(n);
  for (int i = 0; i < n; i++) {
    cin >> p[i];
  }
  vector<pair<int, int>> edges;
  set<int> es;
  for (int i = 0; i < m; i++) {
    int x, y;
    cin >> x >> y;
    x--;
    y--;
    edges.push_back({x, y});
    es.insert(i);
  }
  struct query {
    int type;
    int x;
  };
  vector<query> queries;
  for (int i = 0; i < q; i++) {
    int type, x;
    cin >> type >> x;
    x--;
    queries.push_back({type, x});
    if (type == 2) {
      auto it = es.find(x);
      assert(it != es.end());
      es.erase(it);
    }
  }
  for (int ed : es) {
    queries.push_back({2, ed});
  }
  q = queries.size();
  reverse(queries.begin(), queries.end());
  dsu g(n);
  vector<pair<int, int>> info;
  vector<int> par(n, -1);
  for (int i = 0; i < q; i++) {
    const query &qr = queries[i];
    if (qr.type == 1) {
      int rt = g.find(qr.x);
      info.push_back({rt, g.last[rt]});
    } else {
      assert(qr.type == 2);
      const pair<int, int> &e = edges[qr.x];
      int v = e.first, u = e.second;
      v = g.find(v);
      u = g.find(u);
      assert(par[v] == -1);
      assert(par[u] == -1);
      if (v == u) continue;
      par[u] = g.last[v];
      g.unite(v, u);
    }
  }
  reverse(info.begin(), info.end());
  vector<int> nxt(n, -1);
  for (int i = 0; i < n; i++) {
    if (par[i] != -1) {
      nxt[par[i]] = i;
    }
  }
  vector<int> roots;
  for (int i = 0; i < n; i++) {
    if (par[i] == -1) {
      roots.push_back(i);
    }
  }
  vector<int> order(n);
  int next = -1;
  vector<int> pos(n, -1);
  for (int i = 0; i < n; i++) {
    if (next == -1) {
      order[i] = roots.back();
      roots.pop_back();
    } else {
      order[i] = next;
    }
    next = nxt[order[i]];
    pos[order[i]] = i;
  }
  segtree st(n);
  for (int i = 0; i < n; i++) {
    st.update(i, p[order[i]]);
  }
  for (auto &pr : info) {
    int index = st.get(pos[pr.first], pos[pr.second]).mx_ind;
    cout << p[order[index]] << endl;
    st.update(index, 0);
    p[order[index]] = 0;
  }
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  foo();
}
