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;

#define llong long long 
#define len(x) ((int)x.size())
#define rep(i,n) for (int i = -1; ++ i < n; )
#define rep1(i,n) for (int i = 0; i ++ < n; )
#define CONCAT_(x, y) x##y/*{{{*/
#define CONCAT(x, y) CONCAT_(x, y)
#define SPEC(name) CONCAT(name, __LINE__)
#ifdef LOCAL_DEBUG   
int __db_level = 0;
#define clog cerr << string(__db_level * 2, ' ')
struct debug_block {
    string msg;
    debug_block(const string& s): msg(s) { clog << "{ " << msg << endl; ++__db_level; }
    ~debug_block() { --__db_level; clog << "} " << msg << endl; }
};
#define DB(args...) stringstream SPEC(ss); SPEC(ss)<< args; debug_block SPEC(dbbl)(SPEC(ss).str())
#else
#define clog if (0) cerr
#define DB(...)
#endif
#define db(val) "[" #val " = " << val << "]; "
template<class U, class V> ostream& operator<<(ostream& out, const pair<U, V>& p) {
    return out << "(" << p.first << ", " << p.second << ")";
}
template<size_t i, class T> ostream& print_tuple_utils(ostream& out, const T& tup) {
    if constexpr(i == tuple_size<T>::value) return out << ")";
    else return print_tuple_utils<i + 1, T>(out << (i ? ", " : "(") << get<i>(tup), tup);
}
template<class ...U>
ostream& operator<<(ostream& out, const tuple<U...>& tup) { return print_tuple_utils<0, tuple<U...>>(out, tup); }
template<class, typename = void> struct has_const_iterator : false_type {};
template<class T> struct has_const_iterator<T, void_t<typename T::const_iterator>> : true_type {};
template<class T>
typename enable_if<has_const_iterator<T>::value && !is_same<T, string>::value, ostream&>::type
operator<<(ostream& out, const T& container) { 
    auto beg = container.begin(), end = container.end();
    out << "(" << container.size() << ") {";
    if (beg != end) out << *(beg++);
    while (beg != end) out << ", " << *(beg++);
    return out << "}";
}
#define ptrtype(x) typename iterator_traits<x>::value_type
template<class u> vector<ptrtype(u)> $v(u a, u b) { return vector<ptrtype(u)>(a, b); }/*}}}*/
// ACTUAL SOLUTION BELOW ////////////////////////////////////////////////////////////

// Change these
using ans_type = vector<int>;
constexpr bool testing = 0;
constexpr bool print_brute = 0;
constexpr bool multitest = 0;

mt19937 rng(testing ? 177013 : chrono::system_clock::now().time_since_epoch().count());  // or mt19937_64

struct Query {
    int type, u;
    Query() {}
};
const int maxn = 201010;
const int maxm = 303030;
int n, m, q;
int a[maxn];
vector<pair<int, int>> edge_list;
Query qr[maxm];

pair<int, int> it[maxn * 2];
void build(const vector<int>& vals) {
    assert(len(vals) == n);
    rep(i, n) it[i + n] = {vals[i], i};
    for (int i = n - 1; i > 1; --i) {
        it[i] = max(it[2 * i], it[2 * i + 1]);
    }
}

pair<int, int> get_max(int l, int r) {
    pair<int, int> ans(0, -1);
    for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
        if (l & 1) ans = max(ans, it[l++]);
        if (r & 1) ans = max(ans, it[--r]);
    }
    return ans;
}

void set_val(int pos, int new_val) {
    it[pos + n] = {new_val, pos};
    for (pos += n; pos > 1; pos >>= 1) it[pos >> 1] = max(it[pos], it[pos ^ 1]);
}

void read() {
    if constexpr(!testing) {
        cin >> n >> m >> q;
        rep(i, n) cin >> a[i];
        edge_list.clear();
        rep(i, m) {
            int u, v; cin >> u >> v;
            --u; -- v;
            edge_list.emplace_back(u, v);
        }
        rep(i, q) {
            cin >> qr[i].type >> qr[i].u;
            --qr[i].u;
        }
        
    } else {
        ofstream inp("main.inp");
        // generate test
    }
}

void print_ans(ostream& cout, const ans_type& ans) {
    for (auto i: ans) cout << i << '\n';
}

ans_type solve() {
    vector<vector<pair<int, int>>> par(n);
    rep(i, n) {
        par[i].push_back(make_pair(INT_MAX, i));
    }
    
    vector<int> dsu(n, -1);
    function <int(int)> find_set = [&](int u) {
        return dsu[u] < 0  ? u : dsu[u] = find_set(dsu[u]); };
    
    auto join = [&](int u, int v) -> pair<int, int> {
        u = find_set(u);
        v = find_set(v);
        if (u == v) return {-1, -1};
        if (-dsu[u] < -dsu[v]) swap(u, v);
        dsu[u] += dsu[v];
        dsu[v] = u;
        return {u, v};
    };
    
    vector<vector<int>> tree(n);
    vector<bool> end_edges(m, true);
    
    rep(i, q) {
        if (qr[i].type == 2) end_edges[qr[i].u] = true;
    }
    
    auto make_tree_edge = [&](int u, int v, int id) {
        auto [p, c] = join(u, v);
        if (p == -1) return ;
        tree[p].push_back(c);
        par[c].emplace_back(id, p);
    };
    
    rep(i, m) {
        if (!end_edges[i]) continue;
        auto [u, v] = edge_list[i];
        make_tree_edge(u, v, INT_MAX);
    }
    
    for (int i = q; i--; ) {
        if (qr[i].type == 1) continue;
        auto [u, v] = edge_list[qr[i].u];
        make_tree_edge(u, v, i);
    }
    
    vector<int> start(n), stop(n);
    vector<int> vals;
    function<void(int)> dfs = [&](int u) {
        start[u] = len(vals);
        vals.push_back(a[u]);
        for (auto v: tree[u]) {
            dfs(v);
        }
        stop[u] = len(vals);
    };
    
    rep(i, n) {
        if (dsu[i] < 0) dfs(i);
    }
    
    build(vals);
    
    vector<int> ans;
    rep(i, q) {
        if (qr[i].type == 2) continue;
        int u = qr[i].u;
        while (par[u].back().first < i) {
            par[u].pop_back();
        }
        int cur_p = par[u].back().second;
        auto mx = get_max(start[cur_p], stop[cur_p]);
        ans.push_back(mx.first);
        set_val(mx.second, 0);
    }
    
    return ans;
}

ans_type brute() {
    return ans_type();
}

int main(void) {
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int ntest = testing ? 1000 : 1; 
    if (multitest and !testing) cin >> ntest;
    
    rep1(testcase, ntest) {
        DB(testcase);
        read();
        if constexpr (!testing) {
            print_ans(cout, solve());
            if (print_brute) print_ans(cout << endl << "====" << endl, brute());
        } else {
            auto u = solve();
            auto v = brute();
            assert(u == v);
        }
    }
    

    return 0;
}

// Remember:
// - Multitest? REFRESHING the data!!!
// - Constrains for each set of data may differs. Should NOT USE the same max constant (maxn)
//   for all of them.
// vim: foldmethod=marker

