#include <bits/stdc++.h>
using namespace std;

//#define int long long

const int N = 5e5 + 7;

int t[N], qq[N], u[N], v[N], a[N], r[N], par[N], sz[N];

set <pair <int, int> > st[N];

pair <int, int> edges[N], e;

vector <int> adj[N];

void dfs(int x, vector <int> &vrtx) {
	vrtx.push_back(x);
	for(int y: adj[x])
		dfs(y, vrtx);
}

int find(int x) {
	return par[x] == x ? x : find(par[x]);
}

int merge(int a, int b) {
	a = find(a);
	b = find(b);
	if(a == b) return false;
	if(sz[a] < sz[b]) swap(a, b);
	par[b] = a;
	sz[a] += sz[b];
	adj[a].push_back(b);
	e = make_pair(a, b);
	return true;
}

int32_t main() {
	ios_base :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n, m, q; cin >> n >> m >> q;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		par[i] = i;
		sz[i] = 1;
	}
	for(int i = 1; i <= m; i++) {
		cin >> u[i] >> v[i];
	}
	for(int i = 1; i <= q; i++) {
		cin >> t[i] >> qq[i];
		if(t[i] == 2) r[qq[i]] = true;
	}

	for(int i = 1; i <= m; i++) if(!r[i]) {
		merge(u[i], v[i]);
	}

	for(int i = q; i >= 1; i--) if(t[i] == 2) {
		r[i] = merge(u[qq[i]], v[qq[i]]);
		if(r[i]) edges[i] = e;
	}

	for(int i = 1; i <= n; i++) {
		int x = find(i);
		st[x].insert(make_pair(a[i], i));
	}

	for(int i = 1; i <= q; i++) {
		if(t[i] == 1) {
			int vv = find(qq[i]);
			auto z = *st[vv].rbegin(); st[vv].erase(z);
			cout << a[z.second] << "\n";
			a[z.second] = 0;
			st[vv].insert(make_pair(a[z.second], z.second));
		} else if(r[i]) {
			int aa, bb; tie(aa, bb) = edges[i];
			adj[aa].pop_back();
			par[bb] = bb;
			aa = find(aa);
			vector <int> vrtx;
			dfs(bb, vrtx);
			for(int x: vrtx) {
				st[aa].erase(make_pair(a[x], x));
				st[bb].insert(make_pair(a[x], x));
			}
		}
	}
}

#include <iostream>
#include <vector>
#include <set>

using namespace std;

const int NMAX = 2e5;
const int MMAX = 3e5;
const int QMAX = 5e5;

int n, N, M, Q;
int p[NMAX + 2];

pair <int, int> edges[MMAX + 2];
set < int > edgesSet;

struct Query
{
    int type, x;
};

Query qr[QMAX + MMAX + 2];

int dad[NMAX + MMAX + 2], boss[QMAX + 2];
vector <int> g[NMAX + MMAX + 2];

int Root(int node)
{
    if(node == dad[node])
        return node;

    return dad[node] = Root(dad[node]);
}

void join(int p, int q)
{
    p = Root(p);
    q = Root(q);

    if(p != q)
    {
        ++N;
        dad[p] = N;
        dad[q] = N;

        g[N].push_back(p);
        g[N].push_back(q);
    }
}

bool vis[NMAX + MMAX + 2];
vector <int> eulerTour;

int lf[NMAX + MMAX + 2], rg[NMAX + MMAX + 2];

void dfs(int node)
{
    vis[node] = true;
    eulerTour.push_back(node);
    lf[node] = (int)eulerTour.size();

    for(auto it : g[node])
        dfs(it);

    rg[node] = (int)eulerTour.size();
}

struct Aint
{
    int v[4 * (NMAX + MMAX)];
    int p[4 * (NMAX + MMAX)];

    void Update(int node, int st, int dr, int pos, int val)
    {
        if(st == dr)
        {
            v[node] = val;
            p[node] = pos;
            return ;
        }

        int mid = (st + dr) >> 1;
        if(pos <= mid)
            Update(2 * node, st, mid, pos, val);
        else
            Update(2 * node + 1, mid + 1, dr, pos, val);

        if(v[2 * node] > v[2 * node + 1])
            v[node] = v[2 * node], p[node] = p[2 * node];
        else
            v[node] = v[2 * node + 1], p[node] = p[2 * node + 1];
    }

    pair <int, int> Query(int node, int st, int dr, int l, int r)
    {
        if(l <= st && dr <= r)
            return {v[node], p[node]};

        if(r < st || dr < l)
            return {-1, -1};

        int mid = (st + dr) >> 1;

        pair <int, int> a1 = Query(2 * node, st, mid, l, r);
        pair <int, int> a2 = Query(2 * node + 1, mid + 1, dr, l, r);

        if(a1.first > a2.first)
            return a1;

        return a2;
    }
};

Aint aint;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> M >> Q;

    for(int i = 1; i <= n; i++)
        cin >> p[i];
    N = n;

    for(int i = 1; i <= M; i++)
    {
        int x, y;
        cin >> x >> y;
        edges[i] = {x, y};
        edgesSet.insert(i);
    }

    for(int i = 1; i <= Q; i++)
    {
        int t, x;
        cin >> t >> x;
        qr[i] = {t, x};
        if(t == 2) edgesSet.erase(x);
    }

    while(!edgesSet.empty())
    {
        int edg = *edgesSet.begin();
        edgesSet.erase(edg);
        qr[++Q] = {2, edg};
    }

    for(int i = 1; i <= N + M; i++)
        dad[i] = i;

    for(int i = Q; i >= 1; i--)
    {
        if(qr[i].type == 2)
        {
            int edg = qr[i].x;
            join(edges[edg].first, edges[edg].second);
        }
        else
            boss[i] = Root(qr[i].x);
    }

    for(int i = N; i >= 1; i--)
        if(!vis[i])
            dfs(i);

    for(int i = 1; i <= n; i++)
        aint.Update(1, 1, N, lf[i], p[i]);

    for(int i = 1; i <= Q; i++)
    {
        if(qr[i].type == 2) continue;

        pair <int, int> res = aint.Query(1, 1, N, lf[boss[i]], rg[boss[i]]);
        cout << res.first << '\n';
        aint.Update(1, 1, N, res.second, 0);
    }

    return 0;
}

#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x,I=y+1;i<I;++i)
#define per(i,x,y) for(int i=x,I=y-1;i>I;--i)
using namespace std;
using ll=long long;
void cmax(int&x,const int&y){x=x>y?x:y;}
void cmin(int&x,const int&y){x=x<y?x:y;}
template<class T>istream&operator>>(istream&in,vector<T>&V){for(auto&x:V)in>>x;return in;}
template<class T>ostream&operator<<(ostream&out,const vector<T>&V){for(auto x:V)out<<x<<' ';return out;}
template<class T>void sort(vector<T>&V){sort(V.begin(),V.end());}
template<class T>void reverse(vector<T>&V){reverse(V.begin(),V.end());}
template<class T>int SZ(const vector<T>&V){return (int)V.size();}
void debug(){cerr<<"whxorz"<<'\n';}

const int N = 2e5 + 5;
const int M = 3e5 + 5;
const int Q = 5e5 + 5;
int n, m, q;
int _p[N];
int opt[Q], opx[Q];
struct Edge {
	int u, v, w;
	bool operator <(const Edge &rhs) const { return w > rhs.w; }
} edge[M];

const int T = N << 1;
vector <int> g[T];
int fa[T], val[T];
const int K = 19;
int f[T][K];

int find(const int &x) {
	if (x == fa[x])
		return x;
	else
		return fa[x] = find(fa[x]);
}

int sz[T], dfn[T], idx = 0;
void dfs(int u) {
	sz[u] = 1; dfn[u] = ++idx;
	for (auto v : g[u])
		if (!dfn[v]) { f[v][0] = u; dfs(v), sz[u] += sz[v]; }
}

pair <int, int> s[T << 2];
void up(int p) { s[p] = max(s[p << 1], s[p << 1 | 1]); }

void modify(int l, int r, int p, int x, int v) {
	if (l == r) { s[p] = make_pair(_p[v], v); return; }
	int mid = l + r >> 1;
	if (x <= mid) { modify(l, mid, p << 1, x, v); }
	else { modify(mid + 1, r, p << 1 | 1, x, v); }
	up(p);
}

pair <int, int> query(int ql, int qr, int l, int r, int p) {
	if (ql <= l && r <= qr) { return s[p]; }
	int mid = l + r >> 1;
	if (qr <= mid) { return query(ql, qr, l, mid, p << 1); }
	else if (ql > mid) { return query(ql, qr, mid + 1, r, p << 1 | 1); }
	else { return max(query(ql, qr, l, mid, p << 1), query(ql, qr, mid + 1, r, p << 1 | 1)); }
}

int main(){
	ios::sync_with_stdio(false); cin.tie(NULL);
	cin >> n >> m >> q;
	for (int i = 1; i <= n; i++) { cin >> _p[i]; }
	for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; edge[i].u = u; edge[i].v = v; edge[i].w = q + 1; }
	for (int i = 1; i <= q; i++) { cin >> opt[i] >> opx[i]; }
	for (int i = 1; i <= q; i++) { if (opt[i] == 2) { edge[opx[i]].w = i; } }
	sort(edge + 1, edge + m + 1);
	int tot = n;
	for (int i = 1; i <= n * 2; i++) { fa[i] = i; }
	for (int i = 1; i <= m; i++) {
		int x = find(edge[i].u), y = find(edge[i].v);
		if (x == y) { continue; }
		++tot; fa[x] = tot; fa[y] = tot; g[tot].push_back(x); g[tot].push_back(y); val[tot] = edge[i].w;
	}
	for (int i = tot; i >= 1; --i) if (!dfn[i]) { dfs(i); }
	for (int j = 1; j < K; j++) {
		for (int i = 1; i <= tot; i++) { f[i][j] = f[f[i][j - 1]][j - 1]; }
	}
	for (int i = 1; i <= n; i++) { modify(1, tot, 1, dfn[i], i); }
	for (int i = 1; i <= q; i++) {
		if (opt[i] == 2) { continue; }
		int x = opx[i];
		for (int j = K - 1; j >= 0; --j) {
			if (val[f[x][j]] > i) { x = f[x][j]; }
		}
		auto res = query(dfn[x], dfn[x] + sz[x] - 1, 1, tot, 1);
		int v = res.second; cout << _p[v] << '\n'; _p[v] = 0; modify(1, tot, 1, dfn[v], v);
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;

#define endl "\n"
#define LL long long
#define ULL unsigned long long
const LL        INF = 1LL<<59;
const double    PI = 2.0 * acos(0.0);

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;
typedef vector<int> vi;
typedef vector<LL> vl;
typedef vector<pii> vii;
typedef vector<pll> vll;

//// Including Policy Based DS
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//
/////cout<<*X.find_by_order(1)<<endl;
/////cout<<X.order_of_key(-5)<<endl;
//
//typedef tree<
//int,
//null_type,
//less< int >,
//rb_tree_tag,
//tree_order_statistics_node_update>
//ordered_set;

#define READ        freopen("in.txt","r",stdin)
#define WRITE       freopen("out.txt","w",stdout)
#define BOOST		ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define sf 			scanf
#define pf 			printf
#define F  			first
#define S  			second
#define pb 			push_back
#define NL			pf("\n")
#define ALL(v)		v.begin(),v.end()
#define si(x)		sf("%d",&x);
#define sii(x,y)	sf("%d%d",&x,&y);
#define siii(x,y,z)	sf("%d%d%d",&x,&y,&z);
#define sl(x)		sf("%lld",&x);
#define sll(x,y)	sf("%lld%lld",&x,&y);
#define slll(x,y,z)	sf("%lld%lld%lld",&x,&y,&z);
#define sqr(x)      ( (x) * (x) )
#define mem(x,y) 	memset(x,y,sizeof x )
#define ch 			printf("Came Here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
#define deb(x)      cerr<<#x<<" :: "<<x<<"\n"
#define SV(v)		sort(v.begin(),v.end())
#define SVR(v,cmp)	sort(v.begin(),v.end(),cmp)
#define FOR(i,n)	for(int i=0;i<n;i++)
#define cnd			tree[idx]
#define lc			tree[idx*2]
#define rc			tree[idx*2+1]
#define lnd 		(2*idx),(b),( (b+e) /2 )
#define rnd 		((2*idx)+1),(((b+e)/2)+1),(e)

// graph direction array [4]
int X[4]={0,0,-1,1};
int Y[4]={1,-1,0,0};
// graph direction array [8]
//int X[8]={0,0,1,-1,-1,1,1,-1};
//int Y[8]={1,-1,0,0,-1,-1,1,1};
// Bishop direction array [8]
//int BX[8]={0,0,1,-1,-1,1,1,-1};
//int BY[8]={1,-1,0,0,-1,-1,1,1};
// Knight Direction Array
//int KX[8] = {1,1,2,2,-1,-1,-2,-2};
//int KY[8] = {2,-2,1,-1,2,-2,1,-1};

// Bit Operations
#define popcountL   __builtin_popcountll
#define popcount    __builtin_popcount
inline bool checkBit(int N,int pos){return (bool)(N & (1<<pos));} // check bit
inline int setBit(int N,int pos){ return N=N | (1<<pos);}// set bit
inline int unsetBit(int N,int pos){	return N=( N & ( ~( 1<<pos ) ) );}// unset bit
inline int toggleBit(int N,int pos){ return N = ( N ^(1<<pos) ); }// toggle bit

inline LL modMul(LL a, LL b,LL mod){
    LL ans = 0;
    a = a % mod;
    while (b > 0){
        if ( b % 2 )ans = (ans%mod+ a%mod) % mod;
        a = (a%mod * 2%mod) % mod;
        b /= 2;
    }
    return ans % mod;
}
inline LL powerMod(LL a,LL b,LL mod){
	if(b==0)return 1LL%mod;
	LL x=powerMod( a,b/2,mod );
	x = ( x%mod * x%mod ) % mod;
	if( b%2==1 )x = ( x%mod * a%mod ) % mod;
	return x%mod;
}
inline LL lcm( LL a,LL b ){
	LL g = __gcd(a,b);
	return ((a/g) * b);
}

//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
const int mx = 2e6+5;

int arr[mx];

vi dg[mx];
int par[mx];
int find_par(int u){
    if( u == par[u] )return u;
    return par[u] = find_par(par[u]);
}
int compo;
void merge_set(int u,int v){
    int a = find_par(u);
    int b = find_par(v);
    if(a!=b){
        compo++;
        par[compo] = compo;
        par[a] = compo;
        par[b] = compo;
        dg[compo].pb(a);
        dg[compo].pb(b);
    }
}

int st[mx];
int fin[mx];
bool erased[mx];
pii E[mx];
pii Q[mx];
vi queryNodes;
int __tim;
void dfs(int u,int p){
    st[u] = ++__tim;
    for(int v:dg[u]){
        if(v!=p){
            dfs(v,u);
        }
    }
    fin[u] = ++__tim;
}

pii tree[4*mx];
void update(int idx,int b,int e,int pos,pii v){
    if(b==e && b==pos){
        cnd = v;
        return;
    }
    int mid = (b+e)>>1;
    if(pos<=mid)update(lnd,pos,v);
    else update(rnd,pos,v);
    cnd = max(lc,rc);
}

pii query(int idx,int b,int e,int l,int r){
    if( l>e || r<b )return pii(0,0);
    if( l<=b && r>=e )return cnd;
    return max(query(lnd,l,r),query(rnd,l,r));
}

int main(){
    BOOST;
    #ifdef MujahidPC
        double start = clock();
//        READ;
//        WRITE;
    #endif
    int t,n,m,q;

    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>arr[i];
    }

    FOR(i,m){
        cin>>E[i+1].first>>E[i+1].second;
    }

    FOR(i,q){
        int x,y;
        cin>>x>>y;
        Q[i] = pii(x,y);
        if(x==2){
            erased[y] = 1;
        }
    }
    compo = n;
    for(int i=1;i<=n;i++)par[i] = i;
    __tim = 0;
    for(int i=1;i<=m;i++){
        if(!erased[i]) {
            merge_set(E[i].first,E[i].second);
        }
    }

    for(int i=q-1;i>=0;i--){
        if( Q[i].first == 1 ){
            int p = find_par(Q[i].second);
            queryNodes.pb(p);
        }
        else{
            int id = Q[i].second;
            int u = E[id].first;
            int v = E[id].second;
            merge_set(u,v);
        }
    }

    for(int i=1;i<=compo;i++){
        if( find_par(i) == i ){
            dfs(i,-1);
        }
    }

    int lst = fin[compo] + 1;
    for(int i=1;i<=compo;i++){
        update(1,1,lst,st[i],pii(arr[i],i));
    }
    reverse(ALL(queryNodes));
    for(int v:queryNodes){
        int l = st[v],r = fin[v];
        pii cur = query(1,1,lst,l,r);
        cout<<cur.first<<endl;
        if( cur.first!=0 ){
            int u = cur.second;
            update(1,1,lst,st[u],pii(0,0));
        }
    }

    #ifdef MujahidPC
        double tim = (clock() - start)/CLOCKS_PER_SEC;
        cerr<<"Running Time : "<<tim<<" \n";
    #endif
    return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=600010,M=300010,Q=500010;
struct edge1{
	int u,v,flag;
}d1[M];
struct edge{
	int y,next;
}data[N];
struct qry{
	int x,tp;
}q1[Q];
int n,m,q,num,num1,num2,p1[N],dfn[N],tid[N],lst[N],fa[N],h[N],pos[N],tree[N*4];
inline int read(){
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x;
}
int getfa1(int x){
	if(fa[x]!=x)fa[x]=getfa1(fa[x]);
	return fa[x];
}
inline void addedge(int u,int v){
	data[++num].y=v,data[num].next=h[u],h[u]=num;
}
void dfs(int u){
	dfn[u]=++num2;tid[num2]=u;
	for(int i=h[u],v;i!=-1;i=data[i].next){
		v=data[i].y;dfs(v);
	}
	lst[u]=num2;
}
void print(int p,int pa,int pb){
	printf("%d:%d-%d mx%d pos%d\n",p,pa,pb,tree[p],tree[p]);
	if(pa==pb)return;
	int mid=(pa+pb)>>1;
	print(p<<1,pa,mid);print(p<<1|1,mid+1,pb);
}
inline max1(int i,int j){return i>j?i:j;}
inline void update(int p){tree[p]=max1(tree[p<<1],tree[p<<1|1]);}
void build(int p,int pa,int pb){
	if(pa==pb){tree[p]=p1[tid[pa]];pos[p1[tid[pa]]]=p;return;}
	int mid=(pa+pb)>>1;
	build(p<<1,pa,mid);build(p<<1|1,mid+1,pb);
	update(p);
}
int query(int p,int pa,int pb,int a,int b){
	if(a<=pa&&pb<=b)return tree[p];
	int mid=(pa+pb)>>1,q1=0,q2=0;
	if(a<=mid)q1=query(p<<1,pa,mid,a,b);
	if(mid<b)q2=query(p<<1|1,mid+1,pb,a,b);
	return max1(q1,q2);
}
int main(){
//	freopen("cf1417f.in","r",stdin);
//	freopen("cf1417f.out","w",stdout);
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;++i)p1[i]=read(),fa[i]=i;
	for(int i=1;i<=m;++i)d1[i].u=read(),d1[i].v=read(),d1[i].flag=1;
	for(int i=1;i<=q;++i){
		q1[i].tp=read(),q1[i].x=read();
		if(q1[i].tp==2)d1[q1[i].x].flag=0;
	}
	num=0;memset(h,-1,sizeof h);
	for(int i=1,uu,vv;i<=m;++i)
		if(d1[i].flag){
			uu=getfa1(d1[i].u),vv=getfa1(d1[i].v);
			fa[uu]=vv;
		}
	for(int i=1,x;i<=n;++i){
		x=getfa1(i);if(x!=i)addedge(x,i);
	}
	num1=n;
	for(int i=q,uu,vv;i>=1;--i){
		if(q1[i].tp==1){
			q1[i].x=getfa1(q1[i].x);
			//printf("%d %d\n",i,q1[i].x);
		}else{
			uu=getfa1(d1[q1[i].x].u),vv=getfa1(d1[q1[i].x].v);
			if(uu==vv)continue;
			p1[++num1]=0;
			fa[uu]=fa[vv]=fa[num1]=num1;
			addedge(num1,uu),addedge(num1,vv);
		}
	}
	p1[num1+1]=0;
	for(int i=1;i<=num1;++i)if(getfa1(i)==i)addedge(num1+1,i);
//	for(int i=1;i<=num1+1;++i){
//		printf("%d:",i);
//		for(int j=h[i];j!=-1;j=data[j].next)printf("%d ",data[j].y);
//		printf("\n");
//	}
	num2=0;dfs(num1+1);
//	for(int i=1;i<=num1+1;++i)printf("%d %d %d\n",i,dfn[i],lst[i]);
	build(1,1,num2);tree[0]=-1;
//	print(1,1,num2);printf("\n");
	for(int i=1,x,y;i<=q;++i){
		if(q1[i].tp==2)continue;
		y=query(1,1,num2,dfn[q1[i].x],lst[q1[i].x]);
		printf("%d\n",y);
		if(y!=0){
			x=pos[y];tree[x]=0;x>>=1;
			while(x){update(x);x>>=1;}
		}
//		print(1,1,num2);printf("\n");
	}
	return 0;
}

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<ctime>
#include<climits>
#define ll long long
#define MAXN 200005
#define MAXM 300005
#define MAXQ 500004
using namespace std;
inline ll read(){
	ll x=0,f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f*=-1;s=getchar();}
	while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+s-'0';s=getchar();}
	return f>0?x:-x;
}
int n=read(),m=read(),q=read(),w[MAXN],q1,q2,u[MAXM],v[MAXM];
int c[MAXQ],gp[MAXQ];
bool del[MAXM],st[MAXQ];
int f[MAXN*3],p,IN=n,IM,ls[MAXN<<1],rs[MAXN<<1],ld[MAXN<<1],rd[MAXN<<1],tp[MAXN],fa[MAXN];
inline int findset(int x){return fa[x]==0?x:(fa[x]=findset(fa[x]));}
inline int MAX(int x,int y){return w[x]>w[y]?x:y;}
inline void dfs(int x){
	if(x==0)return;
	ld[x]=IM,dfs(ls[x]),dfs(rs[x]);
	if(x<=n)IM++,f[p+IM]=x;
	rd[x]=IM;
}
inline int zero(int x){
	int res=w[x];
	for(w[x]=0,x=p+rd[x]>>1;x>0;x>>=1)f[x]=MAX(f[x<<1],f[x<<1|1]);
	return res;
}
inline int sch(int l,int r){
	int res=0;
	for(l=p+l-1,r=p+r+1;(l^1)!=r;l>>=1,r>>=1){
		if((l&1)^1)res=MAX(f[l^1],res);
		if(r&1)res=MAX(f[r^1],res);
	}
	return res;
}
int main()
{
	for(int i=1;i<=n;i++)w[i]=read(),tp[i]=i;
	for(int i=1;i<=m;i++)u[i]=read(),v[i]=read();
	for(int i=1;i<=q;i++){
		st[i]=read()-1,c[i]=read();
		if(st[i])del[c[i]]=1;
	}
	for(int i=1;i<=m;i++)
		if(!del[i])
			if(findset(u[i])!=findset(v[i])){
				IN++,ls[IN]=tp[findset(u[i])],rs[IN]=tp[findset(v[i])];
				fa[findset(v[i])]=findset(u[i]),tp[findset(u[i])]=IN;
			}
	for(int i=q;i>0;i--){
		if(st[i]){
			int x=u[c[i]],y=v[c[i]];
			if(findset(x)!=findset(y)){
				IN++,ls[IN]=tp[findset(x)],rs[IN]=tp[findset(y)];
				fa[findset(y)]=findset(x),tp[findset(x)]=IN;
			}
		}
		else gp[i]=tp[findset(c[i])];
	}
	for(p=1;p<n+2;p<<=1);
	for(int i=IN;i>0;i--)if(!rd[i])dfs(i);
	for(int i=p-1;i>0;i--)f[i]=MAX(f[i<<1],f[i<<1|1]);
	for(int i=1;i<=q;i++)
		if(!st[i])printf("%d\n",zero(sch(ld[gp[i]]+1,rd[gp[i]])));
	return 0;
}

#include<bits/stdc++.h>
#define N 400010
#define M 300010
#define Q 500010
#define D 25
using namespace std;
template<typename T> void read(T &X){
	X=0;char C=getchar();T Sig=1;
	for (;!isdigit(C);C=getchar()) if (C=='-') Sig=-1;
	for (; isdigit(C);C=getchar()) X=(X<<3)+(X<<1)+C-'0';
	X*=Sig;
}
template<typename T> void write(T x){
	if (x<0){putchar('-');x=-x;}
	T y=0;int wei=0;
	while (x>9){y=y*10+x%10;x/=10;++wei;}putchar(x+48);
	while (wei--){putchar(y%10+48);y/=10;}
}
int n,m,q;
int w[N+M];
int pos[N+M];
struct rec{
	int u,v;
	bool flag;
	void rd(){
		read(u);
		read(v);
		flag=true;
		return;
	}
};
rec r[M];
struct ques{
	int op,x;
	void rd(){
		read(op);
		read(x);
		return;
	}
};
ques que[Q];
void get_data(){
	read(n);read(m);read(q);
	for (int i=1;i<=n;i++) read(w[i]);
	for (int i=1;i<=m;i++) r[i].rd();
	for (int i=1;i<=q;i++) que[i].rd();
	return;
}
int f[N+M];
int what[N+M];
int cnt;
int par(int x){
	while (x^f[x]) x=f[x]=f[f[x]];
	return x;
}
void merge(int x,int y){
	f[par(x)]=par(y);
	return;
}
struct side{
	int v,last;
	void get(int x,int y){
		v=x;last=y;
		return;
	}
};
int len;
side c[N+M];
int head[N+M];
int pt[N+M];
int fa[N+M][D];
int h[N+M];
bool vis[N+M];
int tmp;
int lst[N+M];
int lef[N+M];
int rig[N+M];
void put(int x,int y){
	c[++len].get(y,head[x]);
	head[x]=len;
	return;
}
void dfs(int p){
	lst[++tmp]=p;
	lef[p]=tmp;
	vis[p]=true;
	for (int i=head[p];i;i=c[i].last)
		if (!vis[c[i].v]){
			fa[c[i].v][0]=p;
			for (int j=1;fa[c[i].v][j-1];j++,h[c[i].v]++)
				fa[c[i].v][j]=fa[fa[c[i].v][j-1]][j-1];
			dfs(c[i].v);
		}
	rig[p]=tmp;
	return;
}
void prepare(){
	for (int i=1;i<=q;i++)
		if (que[i].op==2) r[que[i].x].flag=false;
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=m;i++)
		if (r[i].flag) merge(r[i].u,r[i].v);
	cnt=n;
	for (int i=1;i<=n;i++){
		if (!what[par(i)]){
			what[par(i)]=++cnt;
			pt[cnt]=q+1;
			f[cnt]=cnt;
		}
		put(what[par(i)],i);
	}
	for (int i=1;i<=n;i++)
		if (f[i]==i) merge(i,what[i]);
	for (int i=q;i;i--)
		if (que[i].op==2){
			int u=par(r[que[i].x].u),v=par(r[que[i].x].v);
			if (u!=v){
				pt[++cnt]=i;
				f[cnt]=cnt;
				put(cnt,u);
				put(cnt,v);
				merge(u,cnt);
				merge(v,cnt);
			}
		}
	for (int i=1;i<=cnt;i++) h[i]=-1;
	for (int i=1;i<=cnt;i++) if (f[i]==i) dfs(i);
	for (int i=1;i<=n;i++) pos[w[i]]=i;
	return;
}
struct Segment_Tree{
	struct node{
		int lef,rig,v;
	};
	node tr[(N+M)<<2];
	void pushup(int i){
		tr[i].v=max(tr[i<<1].v,tr[i<<1|1].v);
		return;
	}
	void build(int i,int L,int R){
		tr[i].lef=L;
		tr[i].rig=R;
		if (L==R){
			tr[i].v=w[lst[L]];
			return;
		}
		int mid=(L+R)>>1;
		build(i<<1,L,mid);
		build(i<<1|1,mid+1,R);
		pushup(i);
		return;
	}
	void change(int i,int idx){
		if (tr[i].lef==tr[i].rig){
			tr[i].v=0;
			return;
		}
		if (idx<=tr[i<<1].rig) change(i<<1,idx);
		else change(i<<1|1,idx);
		pushup(i);
		return;
	}
	int query(int i,int L,int R){
		if (L<=tr[i].lef&&tr[i].rig<=R) return tr[i].v;
		int res=0;
		if (L<=tr[i<<1].rig) res=query(i<<1,L,R);
		if (R>=tr[i<<1|1].lef) res=max(res,query(i<<1|1,L,R));
		return res;
	}
};
Segment_Tree tree;
int jmp(int id,int x){
	for (int i=h[id];i>=0;i--)
		if (fa[id][i]&&pt[fa[id][i]]>x) id=fa[id][i];
	return id;
}
void count(){
	tree.build(1,1,cnt);
	for (int i=1;i<=q;i++)
		if (que[i].op==1){
			int o=jmp(que[i].x,i);
			int where=pos[tree.query(1,lef[o],rig[o])];
			write(w[where]);putchar('\n');
			if (where) tree.change(1,lef[where]);
			w[where]=0;
		}
	return;
}
int main(){
	get_data();
	prepare();
	count();
	return 0;
}

/*
    Автор кода: Вадим Зинов (zv.proger@yandex.ru)
    Решение задачи A с сайта codeforces.com
*/

#include<bits/stdc++.h>
using namespace std;

#define ALL(first) first.begin(), first.end()
#define FASTIO cin.tie(0); cout.tie(0); ios::sync_with_stdio(0)

using st = size_t;
using pii = pair<int, int>;

inline int readInt() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
    while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
    return x * f;
}

inline void writeInt(const int &a, const char &c) {
    printf("%d%c", a, c);
}

struct tree_of_segments {
    // Структура "Дерево отрезков" с получением и удалением максимума на отрезке
    struct seg_nd;
    st _n;
    seg_nd *root;

    struct seg_nd {
        pii mx = {-1, -1}; // mx значение и индекс
        seg_nd *ln = nullptr, *rn = nullptr;

        void set(int i, int v, int l, int r) {
            if (r - l == 1) {
                mx = {v, i}; return;
            }

            if (!rn) {
                ln = new seg_nd();
                rn = new seg_nd();
            }

            int m = (l + r) / 2;
            if (i < m) ln -> set(i, v, l, m);
            else rn -> set(i, v, m, r);

            mx = max(ln -> mx, rn -> mx);
        }

        pii get_mx (int ls, int rs, int l, int r) {
            if (ls <= l && rs >= r) return mx;
            if (ls >= r || rs <= l) return {-1, -1};
            if (!rn) return {-1, -1};
            int m = (l + r) / 2;
            return max(ln -> get_mx(ls, rs, l, m), rn -> get_mx(ls, rs, m, r));
        }
    };

    tree_of_segments(st n) {
        _n = n;
        root = new seg_nd;
    }

    void set(int i, int v) {
        root -> set(i, v, 0, _n);
    }

    pii mx(int ls, int rs) {
        return root -> get_mx(ls, rs, 0, _n);
    }

    pii mx(pii seg) {
        return root -> get_mx(seg.first, seg.second, 0, _n);
    }
};

vector<vector<int>> gr;

struct dsu {
    // Структура "Система непересекающихся множеств"
    // Позволяет за O(~1) объединять два множества
    // Позволяет за O(~1) находить корень множества
    // Позволяет за O(~1) отвечать, находятся ли 2 эл в одном множестве
    // Не позволяет разделять множества
    // Требует O(N) памяти

    vector<int> _par;
    st _n;

    dsu(st n) {
        // Инициализация за O(N)
        // Записывает каждый элемент в свое множество
        _n = n;
        _par.resize(n + 1);
        for (st i = 1; i <= n; i++) {
            _par[i] = i;
        }
    }

    int par/*ent*/(int i) {
        // Находит корень множества за O(~1)
        // Используется эвристика сжатия, что не позволяет создовать
        //  дерево с большой высотой (во всяком случае лениво ее сжимает)
        //  отсюда O(N) - в случае бамбука -> O(~1)
        if (_par[i] == i) return i;
        return _par[i] = par(_par[i]);
    }

    int uni/*on*/(int a, int b) {
        // Объединяет два множества (если они еще не объединены) за O(~1)
        // Вернет корень от полученного множества
        // Из-за специфичности задачи будут создаваться фиктивные вершины
        // Каждая вершниа - состояние графа в нек момент
        a = par(a); b = par(b);
        if (a == b) return a;
        gr.push_back({a, b});
        _par.push_back(++_n);
        _par[a] = _par[b] = _n;
        return _n;
    }

    int uni/*on*/(pii e) {
        return uni(e.first, e.second);
    }
};

void solve() {
    st n = readInt(), m = readInt(), q = readInt();

    gr.resize(n + 1);

    // Читаем значения на вершнинах (ps)
    vector<int> ps(n + 1);
    for (st i = 1; i <= n; i++)
        ps[i] = readInt();

    // Читаем ребра (es)
    vector<pii> es(m + 1);
    for (st i = 1; i <= m; i++)
        es[i].first = readInt(), es[i].second = readInt();

    // Читаем запросы (qs), es_to_del для дополнения
    // списка запросов удалением оставшихся ребер
    vector<bool> es_to_del(m + 1, true);
    vector<pii> qs(q);
    for (st i = 0; i < q; i++) {
        qs[i].first = readInt();
        qs[i].second = readInt();
        if (qs[i].first == 2) es_to_del[qs[i].second] = false;
    }

    // Дополняем qs запросами на удаление неудаленных ребер
    for (st i = 1; i <= m; i++) {
        if (es_to_del[i]) {
            qs.push_back({2, i});
            q++;
        }
    }

    // Это стек запросов на вывод наибольшего в компоненте
    vector <int> q1s;

    // Разворачиваем список запросов и по нему строим дерево СНМ (snm)
    reverse(ALL(qs));
    dsu snm(n);

    for (auto q: qs) {
        switch (q.first) {
            case 1: // если идет запрос на наибольшее значение - сохраняем "позицию" запроса
                q1s.push_back(snm.par(q.second));
                break;
            case 2: // Добавляем ребро в структуру
                snm.uni(es[q.second]);
        }
    }
    reverse(ALL(q1s));

    // snm построена, теперь для каждого запроса ответом будет наибольшее
    //  значение на вершине в поддереве snm записанного в q1s
    //  но проход по всему поддереву все еще долгое занятие, поэтому
    //  преобразуем snm к ДО следущим образом
    // 1) В порядке эйлерова обхода листья занесем в ДО
    // 2) Заменим вершины из q1s на параметры отрезка который они образуют
    // Теперь получение и удаление максимума будет за O(NLogN)

    tree_of_segments seg(n);
    vector<pii> segs(snm._n + 1, {-1, -1});
    int lst = 0;

    function<void (int)> dfs = [&](int v) {
        if (segs[v] != pii(-1, -1))
            return;
        segs[v].first = lst;
        if ((st) v <= n) seg.set(lst++, ps[v]);
        for (auto &u: gr[v])
            dfs(u);
        segs[v].second = lst;
    };

    for (st i = 1; i <= n; i++) {
        dfs(snm.par(i));
    }

    // Инициировали ДО. Наконец можно переходить к обработке запросов и выводу ответов

    for (auto &x: q1s) {
        auto p = seg.mx(segs[x]);
        seg.set(p.second, 0);
        writeInt(p.first, '\n');
    }
}

int main() {
    FASTIO;
#ifndef LCL
    //freopen("input.txt","r", stdin);
    //freopen("output.txt","w", stdout);
#endif

    int t = 1;
    for (; t--;) {
        solve();
    }
}

#include <bits/stdc++.h>
#define For(i, l, r) for (int i = l; i <= r; i++)
#define Down(i, r, l) for(int i = r; i >= l; i--)
#define mk make_pair
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

inline int read() {
  char ch = getchar();
  int s = 0, f = 1;
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while ('0' <= ch && ch <= '9') {
    s = s * 10 + ch - '0';
    ch = getchar();
  }
  return f * s;
}
const int maxn = 2e5 + 7;
const int maxm = 3e5 + 7;
const int maxq = 5e5 + 7;
int p[maxn], tim[maxq];
struct edge{
    int next, to;
}e[maxn*2];
int cnt1 = 0;
int tree[maxn*2];
inline int makeNode(int t = 0){
    ++cnt1;
    tree[cnt1] = t;
    return cnt1;
}
struct node{
    int u, v;
}tmpEdge[maxm],sortEdge[maxm];
struct que{
    int opt;
    int index;
}query[maxq];

int cnt = 0;
int head[maxn * 2];
bool initEdge[maxm];
inline void addEdge(int u, int v){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}

int fa[maxn * 2];
int getFa(int u){
    if (fa[u] == u) return u;
    else return fa[u]= getFa(fa[u]);
}
const int LOG = 18;
int anc[maxn*2][LOG + 1];
int mi_dfn[maxn*2], mx_dfn[maxn*2], rev[maxn*2];
int dfns = 0;

void dfs(int u){
    For(i, 1, LOG) anc[u][i] = anc[anc[u][i - 1]][i - 1];
    bool isLeaf = 1;
    mi_dfn[u] = maxq;
    for(int i = head[u]; i; i = e[i].next){
        int v= e[i].to;
        isLeaf = 0;
        anc[v][0] = u;
        dfs(v);
        mi_dfn[u] = min(mi_dfn[u], mi_dfn[v]);
        mx_dfn[u] = max(mx_dfn[u], mx_dfn[v]);
    }
    if (isLeaf){
        rev[++dfns] = u;
        mi_dfn[u] = mx_dfn[u] = dfns;
    }
}
int mx[maxn * 4 + 5], mx_pos[maxn * 4 + 5];
	void push_up(int p) {
		if(mx[p << 1] > mx[p << 1 | 1]) {
			mx[p] = mx[p << 1];
			mx_pos[p] = mx_pos[p << 1];
		} else {
			mx[p] = mx[p << 1 | 1];
			mx_pos[p] = mx_pos[p << 1 | 1];
		}
	}
	void build(int P, int l, int r) {
		if(l == r) {
			mx[P] = p[rev[l]];
			mx_pos[P] = l;
			return;
		}
		int mid = (l + r) >> 1;
		build(P << 1, l, mid);
		build(P << 1 | 1, mid + 1, r);
		push_up(P);
	}
	void point_modify(int p, int l, int r, int pos) {
		if(l == r) {
			mx[p] = 0;
			return;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid) {
			point_modify(p << 1, l, mid, pos);
		} else {
			point_modify(p << 1 | 1, mid + 1, r, pos);
		}
		push_up(p);
	}
	pii quer(int p, int l, int r, int ql, int qr) {
		if(ql <= l && qr >= r) {
			return make_pair(mx[p], mx_pos[p]);
		}
		int mid = (l + r) >> 1;
		pii res = mk(0, 0);
		if(ql <= mid) {
			res = quer(p << 1, l, mid, ql, qr);
		}
		if(qr > mid) {
			ckmax(res, quer(p << 1 | 1, mid + 1, r, ql, qr));
		}
		return res;
	}

int getAnc(int u, int t){
    Down(i, LOG, 0){
        if (anc[u][i] && tree[anc[u][i]] <= t){
            u = anc[u][i];
        }
    }
    return u;
}

int main(){
    int n = read();
    int m = read(), q = read();
    For(i, 1, n){
        p[i] = read();
        makeNode();
    }

    For(i, 1 , m){
        tmpEdge[i].u = read();
        tmpEdge[i].v = read();
        initEdge[i] = 1;
    }

    For(i, 1, q){
        query[i].opt = read();
        query[i].index = read();
        if (query[i].opt == 2) initEdge[query[i].index] = 0;
    }

    For(i, 1 ,2*n) fa[i] = i;
    int m1 = 0;
    For(i, 1, m){if (initEdge[i]){sortEdge[++m1] = tmpEdge[i];}}
    Down(i, q, 1){
        if (query[i].opt == 2){
            sortEdge[++m1] = tmpEdge[query[i].index];
        }
        else tim[i] = m1;
    }

    For(i, 1, m1){
        int u = getFa(sortEdge[i].u);
        int v = getFa(sortEdge[i].v);
        if (u == v) continue;
        makeNode(i);
        addEdge(cnt1, u);
        addEdge(cnt1, v);
        fa[u] = fa[v] = cnt1;
    }
    For(i, 1, cnt1){
        if (getFa(i) == (i)) dfs(i);
    }
    build(1, 1,n);
    For(i, 1, q){
        if (query[i].opt == 1){
            int u = query[i].index;
            int v = getAnc(u, tim[i]);
            pii qres = quer(1, 1, n, mi_dfn[v], mx_dfn[v]);
            printf("%d\n", qres.first);
            point_modify(1, 1, n, qres.second);
        }
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char buf[2000005];
int pt=2000000;
char gc(){
	if(pt>=2000000)fread(buf,1,2000000,stdin),pt=0;
	return buf[pt++];
}
int rd(){
	int x=0,ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))x=x*10+ch-'0',ch=gc();
	return x;
}
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],bel[200005],a[200005],used[200005];
vector<int> h[200005];
vector<int> vec[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
int Query(int x){
	while(h[x].size()&&(bel[h[x].back()]!=x||used[h[x].back()]))h[x].pop_back();
	if(!h[x].size())return 0;
	int r=h[x].back();
	return h[x].pop_back(),used[r]=1,r;
}
int main() {
	n=rd(),m=rd(),Q=rd();
	for(int i=1,x;i<=n;i++)x=rd(),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)ex[i]=rd(),ey[i]=rd();
	for(int i=1;i<=Q;i++){
		q[i].opt=rd(),q[i].x=rd();
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for(int i=1;i<=m;i++){
		if(del[i])continue;
		int x=gf(ex[i]),y=gf(ey[i]);
		if(x==y)continue;
		if(sz[x]>sz[y])swap(x,y);
		for(int j:h[x])h[y].push_back(j);
		fa[x]=y,sz[y]+=sz[x];
	}
	for(int i=Q;i>=1;i--){
		int x=ex[q[i].x],y=ey[q[i].x];
		if(q[i].opt==1||gf(x)==gf(y))continue;
		x=gf(x),y=gf(y);
		if(sz[x]>sz[y])swap(x,y);
		q[i].rx=x,q[i].ry=y,fa[x]=y,sz[y]+=sz[x];
		for(int j:h[x])h[y].push_back(j);
	}
	for(int i=1;i<=n;i++){
		for(int j:h[i])vec[j].push_back(i);
		h[i].clear();
	}
	for(int i=1;i<=n;i++)for(int j:vec[i])h[j].push_back(i);
	for(int i=1;i<=n;i++)bel[a[i]]=gf(i);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define ld long double
#define endl "\n"
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define ms(v,x) memset(v,x,sizeof(v))
#define all(v) v.begin(),v.end()
#define ff first
#define ss second
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define per(i, a, b) for(int i = b-1; i>=a ; i--)
#define trav(a, x) for(auto& a : x)
#define allin(a , x) for(auto a : x)
#define Unique(v) sort(all(v));v.erase(unique(all(v)),v.end());
#define sz(v) ((int)v.size())
//#define int long long
using namespace std;
typedef vector<int> vi;
#define y1 abacaba
#define left sefude
#define db(x) cerr <<#x <<" == "<<x << endl;
#define db2(x,y) cerr<<#x <<" == "<<x<<", "<<#y<<" == "<<y<<endl;
#define db3(x,y,z) cerr << #x<<" == "<<x<<", "<<#y<<" == "<<y<<", "<<#z<<" == "<<z<<endl;
#define prl cerr<<"called: "<< __LINE__ << endl;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
inline ll mod(ll n, ll m ){ ll ret = n%m; if(ret < 0) ret += m; return ret; }
ll gcd(ll a, ll b){return (b == 0LL ? a : gcd(b, a%b));}
ll exp(ll a,ll b,ll m){
    if(b==0LL) return 1LL;
    if(b==1LL) return mod(a,m);
    ll k = mod(exp(a,b/2,m),m);
    if(b&1LL){
        return mod(a*mod(k*k,m),m);
    }
    else return mod(k*k,m);
}

const int N = 200100;
int p[N];
pii e[300100],Q[500100];
bool mark[300100];
vi vec[200100];
vi here[300100];
set<pii> vals[N];
int pai[N];
bool sp[300100];
int tam(int x){return sz(vec[pai[x]]);}
void join(int a,int b){
  a=pai[a],b=pai[b];
  if(a==b)return;
  if(tam(a)>tam(b))swap(a,b);
  for(int x : vec[a]){
    vec[b].pb(x);
    pai[x] = b;
  }
  vec[a].clear();
}

inline int maxi(int x){
  x = pai[x];
  pii v = *vals[x].rbegin();
  vals[x].erase(v);
  p[v.ss]=0;
  vals[x].insert(pii(p[v.ss],v.ss));
  return v.ff;
}

// #define DB  0
inline void erase(int a,int b,int id){
  b=pai[b];
  for(int x : here[id]){
    pai[x] = a;
    vals[b].erase(pii(p[x],x));
    vals[a].insert(pii(p[x],x));
  }
}
int32_t main(){
  fastio;
  int n,m,q;
  cin>>n>>m>>q;
  for(int i=1;i<=n;i++){
    cin>>p[i];
    pai[i]=i;
    vec[i].pb(i);
  }
  for(int i=1;i<=m;i++)cin>>e[i].ff>>e[i].ss;
  for(int i=1;i<=q;i++){
    cin >> Q[i].ff>>Q[i].ss;
    if(Q[i].ff==2){
      mark[Q[i].ss]=1;
    }
  }
  for(int i=1;i<=m;i++){
    if(!mark[i]){
      join(e[i].ff,e[i].ss);
    //  if(DB)cout <<"join "<<i<<endl;
    }
  }
  for(int i=q;i>=1;i--){
    if(Q[i].ff==2){
      int id = Q[i].ss;
      if(pai[e[id].ff]!=pai[e[id].ss]){
    //    if(DB)cout <<"oi "<<id<<endl;
        sp[id]=1;
        if(tam(e[id].ff)>tam(e[id].ss)){
          swap(e[id].ff,e[id].ss);
        }
        e[id].ff = pai[e[id].ff];
        here[id] = vec[e[id].ff];
        e[id].ss = pai[e[id].ss];
        join(e[id].ff,e[id].ss);
      }
    }
  }
  for(int i=1;i<=n;i++){
    if(pai[i]==i){
      for(int x : vec[i])
        vals[i].insert(pii(p[x],x));
    }
  }

  for(int i=1;i<=q;i++){
    if(Q[i].ff == 1){
      cout << maxi(Q[i].ss) << endl;
    }else{
      int id = Q[i].ss;
      if(!sp[id])continue;
    //  if(DB)cout << "remove "<<id<<endl;
      erase(e[id].ff,e[id].ss,id);
    }
  }

  // math -> gcd it all
  // Did u check N=1? Did you switch N,M?
}

#include<bits/stdc++.h>
using namespace std;
int Read() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
    while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
    return x * f;
}
int first[800005], nxt[800005], to[800005], tot = 0;
void Add(int x, int y) {
    nxt[++tot] = first[x];
    first[x] = tot;
    to[tot] = y;
}
int ex[500005], ey[500005], vis[500005], rt[500005], tag[500005];
int sz[500005], bh[500005], a[500005], opt[500005], x[500005], vvis[500005], maxn[500005], minn[500005];
int L[500005], R[500005], rev[500005], mx[2000005], Pos[2000005];
void pushup(int o) {
    if(mx[o << 1] > mx[o << 1 | 1])  mx[o] = mx[o << 1], Pos[o] = Pos[o << 1];
    else  mx[o] = mx[o << 1 | 1], Pos[o] = Pos[o << 1 | 1];
}
void build(int o, int l, int r) {
    if(l == r) {mx[o] = a[rev[l]]; Pos[o] = l; return ;}
    int mid = (l + r) >> 1;
    build(o << 1, l, mid);
    build(o << 1 | 1, mid + 1, r);
    pushup(o);
}
void modify(int o, int l, int r, int pos, int val) {
    if(l == r) {mx[o] = val; return ;}
    int mid = (l + r) >> 1;
    if(pos <= mid)  modify(o << 1, l, mid, pos, val);
    else  modify(o << 1 | 1, mid + 1, r, pos, val);
    pushup(o);
}
pair<int, int> my_max(pair<int, int> A, pair<int, int> B) {
    return (A.first > B.first) ? A : B;
}
pair<int, int> query(int o, int l, int r, int nl, int nr) {
    if(nl <= l && r <= nr)  return make_pair(mx[o], Pos[o]);
    int mid = (l + r) >> 1; pair<int, int> ans;
    ans.first = ans.second = 0;
    if(nl <= mid)  ans = my_max(ans, query(o << 1, l, mid, nl, nr));
    if(mid < nr)  ans = my_max(ans, query(o << 1 | 1, mid + 1, r, nl, nr));
    return ans;
}
int findfa(int x) {return rt[x] == x ? x : rt[x] = findfa(rt[x]);}
void dfs(int u) {
    vvis[u] = 1;
    bh[u] += tag[u];
    for(int e = first[u]; e; e = nxt[e]) {
        int v = to[e];
        tag[v] += tag[u];
        dfs(v);
    }
}
signed main() {
    int n = Read(), m = Read(), q = Read();
    for(int i = 1; i <= n; i++)  sz[i] = bh[i] = 1, rt[i] = i, a[i] = Read();
    for(int i = 1; i <= m; i++)  ex[i] = Read(), ey[i] = Read();
    for(int i = 1; i <= q; i++) {
        opt[i] = Read(), x[i] = Read();
        if(opt[i] == 2)  vis[x[i]] = 1;
    }
    for(int i = 1; i <= m; i++) {
        if(!vis[i]) {
            int fx = findfa(ex[i]), fy = findfa(ey[i]);
            if(fx == fy)  continue;
            tag[fx] += sz[fy];
            sz[fy] += sz[fx]; rt[fx] = fy;
            Add(fy, fx);
        }
    }
    for(int i = q; i >= 1; i--) {
        if(opt[i] == 2) {
            int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
            if(fx == fy)  continue;
            tag[fx] += sz[fy];
            sz[fy] += sz[fx]; rt[fx] = fy;
            Add(fy, fx);
        }
    }
    int sum = 0;
    for(int i = 1; i <= n; i++)
        if(!vvis[findfa(i)])  tag[rt[i]] += sum, sum += sz[rt[i]], dfs(rt[i]);
    for(int i = 1; i <= n; i++)
        maxn[i] = minn[i] = bh[i], rt[i] = i, rev[bh[i]] = i;
    for(int i = 1; i <= m; i++) {
        if(!vis[i]) {
            int fx = findfa(ex[i]), fy = findfa(ey[i]);
            if(fx == fy)  continue;
            maxn[fy] = max(maxn[fy], maxn[fx]);
            minn[fy] = min(minn[fy], minn[fx]);
            rt[fx] = fy;
        }
    }
    for(int i = q; i >= 1; i--) {
        if(opt[i] == 2) {
            int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
            if(fx == fy)  continue;
            maxn[fy] = max(maxn[fy], maxn[fx]);
            minn[fy] = min(minn[fy], minn[fx]);
            rt[fx] = fy;
        }
        if(opt[i] == 1)
            L[i] = minn[findfa(x[i])], R[i] = maxn[findfa(x[i])];
    }
    build(1, 1, n);
    for(int i = 1; i <= q; i++) {
        if(opt[i] == 1) {
            pair<int, int> tmp = query(1, 1, n, L[i], R[i]);
            printf("%d\n", tmp.first);
            modify(1, 1, n, tmp.second, 0);
        }
    }
    return 0;
}

#include <algorithm>
#include <cstdio>
using namespace std;
int const maxn = 400003;
int n = 0, m = 0, q = 0, cPoint = 0;
int p[maxn];
struct Edge {
	int u, e;
	int id;
};
Edge E[maxn];
int deleteTime[maxn];
inline bool operator<(Edge const &lhs, Edge const &rhs) { return deleteTime[lhs.id] > deleteTime[rhs.id]; }

int opt[500003], Sec[500003];

int head[maxn], nxt[maxn], to[maxn], cnt = 0;
inline void insert(int u, int e) {
	nxt[++cnt] = head[u];
	head[u] = cnt;
	to[cnt] = e;
}

int fath[maxn];
inline int find(int x) { return fath[x] == x ? x : fath[x] = find(fath[x]); }
int ti[maxn];
void CreateTheTree() {
	std::sort(E + 1, E + m + 1);
	for (int i = 1; i <= 2 * n; ++i)
		fath[i] = i;
	cPoint = n;
	for (int i = 1; i <= m; ++i) {
		if (find(E[i].u) == find(E[i].e)) continue;
		++cPoint;
		ti[cPoint] = deleteTime[E[i].id];
		insert(cPoint, find(E[i].u));
		insert(cPoint, find(E[i].e));
		fath[find(E[i].u)] = cPoint;
		fath[find(E[i].e)] = cPoint;
	}
}

int fa[20][maxn], Ldfn[maxn], Rdfn[maxn];
int dfn[maxn], idfn[maxn];
void dfs(int x, int f) {
	fa[0][x] = f;
	for (int j = 1; j <= 18; ++j)
		fa[j][x] = fa[j - 1][fa[j - 1][x]];
	if (x <= n) {
		Ldfn[x] = Rdfn[x] = dfn[x] = ++dfn[0];
		idfn[dfn[x]] = x;
		return;
	}
	Ldfn[x] = cPoint + 1, Rdfn[x] = 0;
	for (int i = head[x]; i; i = nxt[i]) {
		dfs(to[i], x);
		Ldfn[x] = std::min(Ldfn[x], Ldfn[to[i]]);
		Rdfn[x] = std::max(Rdfn[x], Rdfn[to[i]]);
	}
}

struct MX {
	int v, pos;
};
MX operator|(MX const &lhs, MX const &rhs) { return lhs.v > rhs.v ? lhs : rhs; }
MX mx[maxn << 2];
void CreateSeg(int po, int L, int R) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		mx[po].pos = idfn[L];
		return;
	}
	int mid = (L + R) >> 1;
	CreateSeg(po << 1, L, mid);
	CreateSeg(po << 1 | 1, mid + 1, R);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
void Modify(int po, int L, int R, int x) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		return;
	}
	int mid = (L + R) >> 1;
	if (x <= mid)
		Modify(po << 1, L, mid, x);
	else
		Modify(po << 1 | 1, mid + 1, R, x);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
MX query(int po, int L, int R, int l, int r) {
	if (l <= L && R <= r)
		return mx[po];
	int mid = (L + R) >> 1;
	if (r <= mid)
		return query(po << 1, L, mid, l, r);
	else if (l > mid)
		return query(po << 1 | 1, mid + 1, R, l, r);
	else
		return query(po << 1, L, mid, l, r) | query(po << 1 | 1, mid + 1, R, l, r);
}

int jump(int x, int time) {
	for (int j = 18; ~j; --j)
		if (ti[fa[j][x]] > time)
			x = fa[j][x];
	return x;
}
int main() {
	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].e);
		E[i].id = i;
		deleteTime[i] = q + 1;
	}
	for (int i = 1; i <= q; ++i) {
		scanf("%d %d", opt + i, Sec + i);
		if (opt[i] == 2) deleteTime[Sec[i]] = i;
	}
	CreateTheTree();
	for (int i = 1; i <= cPoint; ++i)
		if (fath[i] == i) dfs(i, 0);
	CreateSeg(1, 1, n);

	for (int i = 1; i <= q; ++i)
		if (opt[i] == 1) {
			int x = jump(Sec[i], i);
			MX res = query(1, 1, n, Ldfn[x], Rdfn[x]);
			printf("%d\n", res.v);
			p[res.pos] = 0;
			Modify(1, 1, n, dfn[res.pos]);
		}
	return 0;
}

#include <algorithm>
#include <cstdio>
using namespace std;
int const maxn = 400003;
int n = 0, m = 0, q = 0, cPoint = 0;
int p[maxn];
struct Edge {
	int u, e;
	int id;
};
Edge E[maxn];
int deleteTime[maxn];
inline bool operator<(Edge const &lhs, Edge const &rhs) { return deleteTime[lhs.id] > deleteTime[rhs.id]; }

int opt[500003], Sec[500003];

int head[maxn], nxt[maxn], to[maxn], cnt = 0;
inline void insert(int u, int e) {
	nxt[++cnt] = head[u];
	head[u] = cnt;
	to[cnt] = e;
}

int fath[maxn];
inline int find(int x) { return fath[x] == x ? x : fath[x] = find(fath[x]); }
int ti[maxn];
void CreateTheTree() {
	std::sort(E + 1, E + m + 1);
	for (int i = 1; i <= 2 * n; ++i)
		fath[i] = i;
	cPoint = n;
	for (int i = 1; i <= m; ++i) {
		if (find(E[i].u) == find(E[i].e)) continue;
		++cPoint;
		ti[cPoint] = deleteTime[E[i].id];
		insert(cPoint, find(E[i].u));
		insert(cPoint, find(E[i].e));
		fath[find(E[i].u)] = cPoint;
		fath[find(E[i].e)] = cPoint;
	}
}

int fa[20][maxn], Ldfn[maxn], Rdfn[maxn];
int dfn[maxn], idfn[maxn];
void dfs(int x, int f) {
	fa[0][x] = f;
	for (int j = 1; j <= 18; ++j)
		fa[j][x] = fa[j - 1][fa[j - 1][x]];
	if (x <= n) {
		Ldfn[x] = Rdfn[x] = dfn[x] = ++dfn[0];
		idfn[dfn[x]] = x;
		return;
	}
	Ldfn[x] = cPoint + 1, Rdfn[x] = 0;
	for (int i = head[x]; i; i = nxt[i]) {
		dfs(to[i], x);
		Ldfn[x] = std::min(Ldfn[x], Ldfn[to[i]]);
		Rdfn[x] = std::max(Rdfn[x], Rdfn[to[i]]);
	}
}

struct MX {
	int v, pos;
};
MX operator|(MX const &lhs, MX const &rhs) { return lhs.v > rhs.v ? lhs : rhs; }
MX mx[maxn << 2];
void CreateSeg(int po, int L, int R) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		mx[po].pos = idfn[L];
		return;
	}
	int mid = (L + R) >> 1;
	CreateSeg(po << 1, L, mid);
	CreateSeg(po << 1 | 1, mid + 1, R);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
void Modify(int po, int L, int R, int x) {
	if (L == R) {
		mx[po].v = p[idfn[L]];
		return;
	}
	int mid = (L + R) >> 1;
	if (x <= mid)
		Modify(po << 1, L, mid, x);
	else
		Modify(po << 1 | 1, mid + 1, R, x);
	mx[po] = mx[po << 1] | mx[po << 1 | 1];
}
MX query(int po, int L, int R, int l, int r) {
	if (l <= L && R <= r)
		return mx[po];
	int mid = (L + R) >> 1;
	if (r <= mid)
		return query(po << 1, L, mid, l, r);
	else if (l > mid)
		return query(po << 1 | 1, mid + 1, R, l, r);
	else
		return query(po << 1, L, mid, l, r) | query(po << 1 | 1, mid + 1, R, l, r);
}

int jump(int x, int time) {
	for (int j = 18; ~j; --j)
		if (ti[fa[j][x]] > time)
			x = fa[j][x];
	return x;
}
int main() {
	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].e);
		E[i].id = i;
		deleteTime[i] = q + 1;
	}
	for (int i = 1; i <= q; ++i) {
		scanf("%d %d", opt + i, Sec + i);
		if (opt[i] == 2) deleteTime[Sec[i]] = i;
	}
	CreateTheTree();
	for (int i = 1; i <= cPoint; ++i)
		if (fath[i] == i) dfs(i, 0);
	CreateSeg(1, 1, n);

	for (int i = 1; i <= q; ++i)
		if (opt[i] == 1) {
			int x = jump(Sec[i], i);
			MX res = query(1, 1, n, Ldfn[x], Rdfn[x]);
			printf("%d\n", res.v);
			if (res.v != 0) {
				p[res.pos] = 0;
				Modify(1, 1, n, dfn[res.pos]);
			}
		}
	return 0;
}

#include <bits/stdc++.h>

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define ar array

using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int maxn = 5e5 + 5;

int U[maxn], V[maxn], type[maxn], id[maxn];
int tin[maxn], tout[maxn], par[maxn], a[maxn], root[maxn];
int N, M, Q;
bool del[maxn];
vector<int> adj[maxn];
ii tr[4 * maxn];

int finds(int u) {
  if (par[u] == u) return u;
  return par[u] = finds(par[u]);
}

void merges(int u, int v) {
  u = finds(u); v = finds(v);
  if (u == v) return;
  ++N;
  par[N] = N;
  par[u] = N;
  par[v] = N;
  adj[N].eb(u); adj[N].eb(v);
}

#define lc id << 1
#define rc id << 1 | 1
void upd(int pos, ii v, int id = 1, int l = 1, int r = N) {
  if (l == r) {
    tr[id] = v;
    return;
  }
  int mid = (l + r) / 2;
  if (pos <= mid) upd(pos, v, lc, l, mid);
  else upd(pos, v, rc, mid + 1, r);
  tr[id] = max(tr[lc], tr[rc]);
}

ii query(int L, int R, int id = 1, int l = 1, int r = N) {
  if (R < l || r < L)
    return mp(0, 0);
  if (L <= l && r <= R)
    return tr[id];
  int mid = (l + r) / 2;
  return max(query(L, R, lc, l, mid), query(L, R, rc, mid + 1, r));
}

void dfs(int u) {
  static int nTime = 0;
  tin[u] = ++nTime;
  for (int v : adj[u]) {
    dfs(v);
  }
  tout[u] = nTime;
}

signed main(void) {
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  #ifdef LOCAL
    freopen("A.INP", "r", stdin);
    freopen("A.OUT", "w", stdout);
  #endif // LOCAL

  cin >> N >> M >> Q;
  iota(par + 1, par + 1 + N, 1);
  for (int i = 1; i <= N; ++i) {
    cin >> a[i];
  }
  for (int i = 1; i <= M; ++i) {
    cin >> U[i] >> V[i];
  }
  for (int i = 1; i <= Q; ++i) {
    cin >> type[i] >> id[i];
    if (type[i] == 2) {
      del[id[i]] = true;
    }
  }

  for (int i = 1; i <= M; ++i) {
    if (!del[i]) {
      merges(U[i], V[i]);
    }
  }

  for (int i = Q; i >= 1; --i) {
    if (type[i] == 1) {
      root[i] = finds(id[i]);
    } else {
      merges(U[id[i]], V[id[i]]);
    }
  }

  for (int i = 1; i <= N; ++i) {
    if (finds(i) == i) {
      dfs(i);
    }
  }

  for (int i = 1; i <= N; ++i) {
    upd(tin[i], mp(a[i], i));
  }

  for (int i = 1; i <= Q; ++i) {
    if (type[i] == 1) {
      ii res = query(tin[root[i]], tout[root[i]]);
      cout << res.fi << '\n';
      upd(tin[res.se], mp(0, res.se));
    }
  }
}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mp make_pair
#define pb push_back
#define VI vector<int>
#define pii pair<int,int>
using namespace std;
const int MAXN = 5e5+10;
int u[MAXN], v[MAXN], per[MAXN];
int su[MAXN], sv[MAXN];
bool rmv[MAXN];
int p[MAXN];
int n, m, q;
int qi[MAXN], val[MAXN], sz[MAXN];
int find(int x){
	if(p[x] == x) return x;
	return p[x] = find(p[x]);
}
void join(int x, int y){
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
bool out[MAXN];
set<int> S[MAXN];
int ss;
int where[MAXN];
vector<pii> g[MAXN];
bool V[MAXN];
int vis;
void dfs(int cur, int prev, int to){
	V[cur] = true;
	where[cur] = to;
	S[to].insert(cur);
	for(int i = 0; i < (int)g[cur].size(); i++){
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs(next, cur, to);
	}
}
void dfs1(int cur, int prev, int from, int to){
	vis++;
	S[from].erase(cur);
	if(!out[cur]) S[to].insert(cur);
	else S[to].insert(0);
	where[cur] = to;
	for(int i = 0; i < (int)g[cur].size(); i++){
		if(rmv[g[cur][i].second]) continue;
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs1(next, cur, from, to);
	}
}
int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(int i = 1; i <= n; i++){
		scanf("%d", &per[i]);
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= m; i++){
		scanf("%d %d", &u[i], &v[i]);
		u[i] = per[u[i]];
		v[i] = per[v[i]];
	}
	for(int i = 0; i < q; i++){
		scanf("%d %d", &qi[i], &val[i]);
		if(qi[i] == 2) rmv[val[i]] = true;
		else val[i] = per[val[i]];
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		if(find(u[i]) == find(v[i])) continue;
		join(u[i], v[i]);
	}
	for(int i = q-1; i >= 0; i--){
		if(qi[i] == 2){
			//ru[i] = find(u[val[i]]);
			//rv[i] = find(v[val[i]]);
			int x = u[val[i]], y = v[val[i]];
			if(find(x) == find(y)){
				su[i] = sv[i] = -1;
				continue;
			}
			su[i] = sz[find(x)];
			sv[i] = sz[find(y)];
			g[x].pb(mp(y,val[i]));
			g[y].pb(mp(x,val[i]));
			join(x, y);

		}
	}
	for(int i = 1; i <= n; i++){
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < (int)g[i].size(); j++){
			int x = i, y = g[i][j].first;
			join(x, y);
		}
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		int x = u[i], y = v[i];
		if(find(x) == find(y)) continue;
		g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
		join(x, y);
	}
	ss = 0;
	memset(V, false, sizeof V);
	for(int i = 1; i <= n; i++){
		if(!V[i]) dfs(i, i, ss++);
	}
	for(int i = 1; i <= m; i++) rmv[i] = false;
	for(int i = 0; i < q; i++){
		if(qi[i] == 1){
			int cur = val[i];
			int w = where[cur];
			int ans = *S[w].rbegin();
			printf("%d\n", ans);
			if(ans){
				out[ans] = true;
				S[w].erase(ans);
				S[w].insert(0);
			}
		}else{
			rmv[val[i]] = true;
			if(su[i] == -1) continue;
			int ei = val[i];
			if(su[i] < sv[i]){
				vis = 0;
				dfs1(u[ei], u[ei], where[u[ei]], ss++);
				if(vis != su[i]){
					printf("%d %d\n", vis, su[i]);
					return 0;
				}
			}else{
				vis = 0;
				dfs1(v[ei], v[ei], where[v[ei]], ss++);
				if(vis != sv[i]){
					printf("%d %d\n", vis, sv[i]);
					return 0;
				}
			}
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
#define fi first
#define se second
#define lc (rt << 1)
#define rc ((rt << 1) | 1)
const int maxn = 2e6 + 50;
int INF = 1e8;
int n, m, q;
struct Edge
{
	int u, to, next;
} edge[maxn * 2], e[maxn];
int k, head[maxn];
void add(int a, int b){
	// printf("%d %d\n", a, b);
	edge[k].to = b;
	edge[k].next = head[a];
	head[a] = k++;
}

int fa[maxn];
int Find(int x){
	if(x == fa[x]) return x;
	return fa[x] = Find(fa[x]);
}

int tot;
void unit(int x, int y){
	x = Find(x), y = Find(y);
	if(x == y) return;
	tot++;
	fa[tot] = fa[x] = fa[y] = tot;
	add(tot, x);
	add(tot, y);
}

int p[maxn], vedge[maxn * 2];
pii qur[maxn];
int res[maxn];
int tim, intim[maxn], outim[maxn], id[maxn];

void dfs(int u, int pre){
	intim[u] = ++tim;
	id[tim] = u;
	for(int i = head[u]; i != -1; i = edge[i].next){
		int to = edge[i].to;
		if(to == pre) continue;
		dfs(to, u);
	}
	outim[u] = tim;
}

pii tree[maxn << 2];

void PushUp(int rt){
	tree[rt] = max(tree[lc], tree[rc]);
}
void Build(int le, int ri, int rt){
	if(le == ri){
		tree[rt] = {p[id[le]], le};
		// printf("le = %d p = %d\n", le, p[id[le]]);
		return ;
	}
	int mid = (le + ri) >> 1;
	Build(le, mid, lc);
	Build(mid + 1, ri, rc);
	PushUp(rt);
}

void Update(int le, int ri, int pos, int rt){
	if(le == ri){
		tree[rt] = {0, 0};
		return ;
	}
	int mid = (le + ri) >> 1;
	if(pos <= mid) Update(le, mid, pos, lc);
	else Update(mid + 1, ri, pos, rc);
	PushUp(rt);
}

pii Query(int le, int ri, int L, int R, int rt){
	if(L <= le && ri <= R){
		return tree[rt];
	}
	int mid = (le + ri) >> 1;
	pii tmp = {0, 0};
	if(L <= mid) tmp = max(tmp, Query(le, mid, L, R, lc));
	if(R > mid) tmp = max(tmp, Query(mid + 1, ri, L, R, rc));
	return tmp;
}

int main(int argc, char const *argv[])
{
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= 2 * n; i++) head[i] = -1, fa[i] = i;
	for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
	for(int i = 1; i <= m; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		e[i] = {a, b, 0};
	}
	for(int i = 1; i <= q; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		qur[i] = {a, b};
		if(a == 2) vedge[b] = 1;
	}
	// printf("\n");
	tot = n;
	for(int i = 1; i <= m; i++){
		if(!vedge[i]){
			unit(e[i].u, e[i].to);
		}
	}
	for(int i = q; i >= 1; i--){
		if(qur[i].fi == 1){
			res[i] = Find(qur[i].se);
			// printf("res[%d] = \n", );
		} else {
			int x = qur[i].se;
			unit(e[x].u, e[x].to);
		}
	}
	for(int i = 1; i <= tot; i++){
		if(Find(i) == i){
			dfs(i, 0);
		}
	}
	// for(int i = 1; i <= tot; i++){
	// 	printf("intim[%d] = %d p = %d\n", i, intim[i], p[i]);
	// }
	Build(1, tot, 1);
	// printf("[%d %d]\n", tree[1].fi, tree[1].se);
	for(int i = 1; i <= q; i++){
		if(qur[i].fi == 1){
			int u = qur[i].se;
			u = Find(u);
			// printf("le = %d ri = %d\n", intim[u], outim[u]);
			pii tmp = Query(1, tot, intim[res[i]], outim[res[i]], 1);
			// printf("[%d %d]\n", tmp.fi, tmp.se);
			printf("%d\n", tmp.fi);
			if(tmp.fi == 0){
				continue;
			}
			Update(1, tot, tmp.se, 1);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

#define pb push_back
#define F first
#define S second
#define ll long long
#define ull unsigned long long
#define ld long double
#define endl '\n'
#define TIME 1.0*clock()/CLOCKS_PER_SEC
#define pii pair < int , int >
#define Endl '\n'

#pragma GCC optimize("Ofast")

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

template <typename T> using ordered_set = tree <T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;

mt19937 gen(chrono::system_clock::now().time_since_epoch().count());

const int mod = 1e9 + 7;
const ll FFTM = 998244353;

const int SX[4] = {0 , 1 , -1 , 0};
const int SY[4] = {1 , 0 , 0 , -1};
const int rx[8] = {1, -1, 0, 0, 1, 1, -1, -1};
const int ry[8] = {0, 0, 1, -1, 1, -1, 1, -1};
const int kx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
const int ky[8] = {2, -2, 2, -2, 1, -1, 1, -1};

typedef cc_hash_table< int, int, hash<int>, equal_to<int>, direct_mask_range_hashing<int>, hash_standard_resize_policy<hash_exponential_size_policy<>, hash_load_check_resize_trigger<true>, true>> ht;

int n, m, q;

vector < int > pr;

vector < pii > quer;

vector < pii > all;

vector < int > a;

vector < bool > can;

vector < vector < int > > G;

vector < int > boss;
vector < int > tin;
vector < int > tout;

int timer = -1;

void init(){
    a.resize(n + q + m, 0);
    all.resize(n + q + m);
    quer.resize(n + q + m);
    can.resize(m, 1);
    pr.resize(n + q + m);
    for (int i = 0;i < n + q + m; ++i)pr[i] = i;
    G.resize(n + q + m);
    boss.resize(n + q + m, -1);
    tin.resize(n + q + m);
    tout.resize(n + q + m);
}

int find_pr(int v){
    if (pr[v] == v)return v;
    else return pr[v] = find_pr(pr[v]);
}

void add(int a, int b){
    a = find_pr(a);
    b = find_pr(b);
    if (a == b)return;
    pr[n] = n;
    pr[a] = n;
    pr[b] = n;
    G[n].pb(a);
    G[n].pb(b);
    n++;
}

void dfs(int v){
    timer++;
    tin[v] = timer;
    for (auto to : G[v]){
        dfs(to);
    }
    tout[v] = timer;
}

vector < pii > t;

void update(int v, int vl, int vr, int pos, pii val){
    if (vl == vr){
        t[v] = val;
        return;
    }
    int mid = (vl + vr) >> 1;
    if (pos <= mid)update(2 * v + 1, vl, mid, pos, val);
    else update(2 * v + 2, mid + 1, vr, pos, val);
    t[v] = max(t[2 * v + 1], t[2 * v + 2]);
}

pii get(int v, int vl, int vr, int l, int r){
    if (vl >= l && vr <= r)return t[v];
    if (vl > r || vr < l)return {0, 0};
    int mid = (vl + vr) >> 1;
    pii q1 = get(2 * v + 1, vl, mid, l, r);
    pii q2 = get(2 * v + 2, mid + 1, vr, l, r);
    return max(q1, q2);
}

int32_t main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
//    freopen("wedding.in", "r", stdin);
//    freopen("wedding.out", "w", stdout);
#endif
    cin >> n >> m >> q;
    init();
    for (int i = 0;i < n; ++i){
        cin >> a[i];
    }
    for (int i = 0;i < m; ++i){
        cin >> all[i].F >> all[i].S;
        all[i].F--;
        all[i].S--;
    }
    for (int i = 0;i < q; ++i){
        cin >> quer[i].F >> quer[i].S;
        quer[i].S--;
        if (quer[i].F == 2){
            can[quer[i].S] = 0;
        }
    }
    for (int i = 0;i < m; ++i){
        if (can[i]){
            add(all[i].F, all[i].S);
        }
    }
    for (int i = q - 1;i >= 0; --i){
        if (quer[i].F == 1){
            boss[i] = find_pr(quer[i].S);
        }else{
            add(all[quer[i].S].F, all[quer[i].S].S);
        }
    }
    for (int i = 0;i < n; ++i){
        if (find_pr(i) == i){
            dfs(i);
        }
    }
    t.resize(4 * n);
    for (int i = 0;i < n; ++i){
        update(0, 0, n - 1, tin[i], {a[i], tin[i]});
    }
    for (int i = 0;i < q; ++i){
        if (quer[i].F == 1){
            pii gt = get(0, 0, n - 1, tin[boss[i]], tout[boss[i]]);
            cout << gt.F << endl;
            if (gt.F != 0)update(0, 0, n - 1, gt.S, {0, 0});
        }
    }
    return 0;
}

#include <bits/stdc++.h>
#define F(i,j,k) for(int i=(j);i<=(k);++i)
#define D(i,j,k) for(int i=(j);i>=(k);--i)
#define rep(it,s) for(__typeof(s.begin()) it=s.begin();it!=s.end();++it)
#define Rep(a,s) for(auto a:s)
#define PB push_back
#define MP make_pair
#define FF first
#define SS second
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
template<class Type>ll quick_pow(Type x,Type y,Type Mod){
    ll res=1;
    while(y){
        if(y&1)res=res*x%Mod;
        x=x*x%Mod,y>>=1;
    }
    return res;
}
template<class Type>ll inv(Type x,Type Mod){return quick(x,Mod-2,Mod);}
namespace IO{
    template <class T>
    inline void read(T &x){
        x=0;int f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
        x*=f;
    }
};
using namespace IO;
const int N=1000005;
struct Edge{
    int u,v;
}e[N];
int n,m,Q,p[N],pos[N],fa[N],flag[N],opt[N],key[N],vcnt,id[N];
int ask[N],top;
vector<int>E[N];
inline void add(int x,int y){E[x].PB(y);}
int find(int x){
    return fa[x]=(fa[x]==x?x:find(fa[x]));
}
void uni(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx!=fy)fa[fx]=fy;
}
void Merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx==fy)return ;
    ++vcnt;
    uni(fx,vcnt),uni(fy,vcnt);
    add(vcnt,fx),add(vcnt,fy);
}
int dfn,Begin[N],End[N],size[N];
void dfs(int x){
    Begin[x]=++dfn,id[dfn]=x;
    size[x]=1;
    Rep(y,E[x]){
        dfs(y);
        size[x]+=size[y];
    }
    End[x]=Begin[x]+size[x]-1;
}
struct SegmentTree{
    int L,R,Mx;
}t[N<<1];
void pushup(int Pos){
    t[Pos].Mx=max(t[Pos<<1].Mx,t[Pos<<1|1].Mx);
}
void build(int Pos,int L,int R){
    t[Pos].L=L,t[Pos].R=R;
    if(L==R){
        t[Pos].Mx=p[id[L]];
        return ;
    }
    int mid=(L+R)>>1;
    build(Pos<<1,L,mid),build(Pos<<1|1,mid+1,R);
    pushup(Pos);
}
int query(int Pos,int L,int R){
    if(L<=t[Pos].L&&t[Pos].R<=R)return t[Pos].Mx;
    if(t[Pos].L>R||t[Pos].R<L)return 0;
    return max(query(Pos<<1,L,R),query(Pos<<1|1,L,R));
}
void modify(int Pos,int x,int delta){
    if(t[Pos].L>x||t[Pos].R<x)return ;
    if(t[Pos].L==t[Pos].R){
        t[Pos].Mx=delta;
        return ;
    }
    modify(Pos<<1,x,delta),modify(Pos<<1|1,x,delta);
    pushup(Pos);
}
int main(){
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    read(n),read(m),read(Q);
    vcnt=n;
    F(i,1,n)read(p[i]),pos[p[i]]=i;
    F(i,1,m){
        read(e[i].u),read(e[i].v);
    }
    F(i,1,Q){
        read(opt[i]),read(key[i]);
        if(opt[i]==2)flag[key[i]]=1;
    }
    F(i,1,n*2)fa[i]=i;
    F(i,1,m)if(!flag[i]){
        Merge(e[i].u,e[i].v);
    }
    D(i,Q,1){
        if(opt[i]==2)Merge(e[key[i]].u,e[key[i]].v);
        else ask[++top]=find(key[i]);
    }
    F(i,1,vcnt)if(fa[i]==i)dfs(i);
    build(1,1,vcnt);
    D(i,top,1){
        int temp=query(1,Begin[ask[i]],End[ask[i]]);
        printf("%d\n",temp);
        if(temp){
            modify(1,Begin[pos[temp]],0);
        }
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;

#define send {ios_base::sync_with_stdio(false);}
#define help {cin.tie(NULL); cout.tie(NULL);}
#define f first
#define s second
#define getunique(v) {sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());}
typedef long long ll;
typedef long double lld;
typedef unsigned long long ull;

template<typename A> ostream& operator<<(ostream &cout, vector<A> const &v);
template<typename A, typename B> ostream& operator<<(ostream &cout, pair<A, B> const &p) { return cout << "(" << p.f << ", " << p.s << ")"; }
template<typename A> ostream& operator<<(ostream &cout, vector<A> const &v) {
	cout << "["; for(int i = 0; i < v.size(); i++) {if (i) cout << ", "; cout << v[i];} return cout << "]";
}
template<typename A, typename B> istream& operator>>(istream& cin, pair<A, B> &p) {
	cin >> p.first;
	return cin >> p.second;
}

mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
// mt19937 rng(61378913);
/* usage - just do rng() */

void usaco(string filename) {
  // #pragma message("be careful, freopen may be wrong")
	freopen((filename + ".in").c_str(), "r", stdin);
	freopen((filename + ".out").c_str(), "w", stdout);
}

// #include <atcoder/all>
// using namespace atcoder;

const lld pi = 3.14159265358979323846;
// const ll mod = 1000000007;
// const ll mod = 998244353;
// ll mod;

/* union by size */
struct dsu {
  int n;
  vector<int> sizes, marks;
  vector<vector<int> > graph;

  void init(int rn) {
    n = rn;
    sizes = vector<int>(n);
    fill(sizes.begin(), sizes.end(), 1);
    marks = vector<int>(n);
    for (int i = 0; i < n; i++) marks[i] = i;
    graph = vector<vector<int> >(n);
  }

  void mark(int m, int node) {
    if (marks[node] == m) return;

    marks[node] = m;

    for (int i: graph[node]) mark(m, i);
  }

  void merge(int a, int b) {
    if (marks[a] == marks[b]) return;
    graph[a].push_back(b);
    graph[b].push_back(a);

    if (sizes[marks[a]] > sizes[marks[b]]) swap(a, b);

    sizes[marks[b]] += sizes[marks[a]];
    sizes[marks[a]] = 0;
    mark(marks[b], a);
  }

  int find(int n) { return marks[n]; }
};

ll n, m, k, q, l, r, x, y, z;
const ll template_array_size = 1e6 + 1600;
int a[template_array_size];
ll b[template_array_size];
ll c[template_array_size];
string s, t;
ll ans = 0;

bool rem[500005];
int comp[500005];
pair<int, int> ed[500005];
pair<int, int> qv[500005];
set<ll> vals[500005];
pair<int, int> targ[500005];
vector<pair<int, int>> edges[500005];
dsu d;
vector<ll> kill;

void relabel(int v, int compv) {
	if (a[v] != 0) {
		kill.push_back(a[v] * n + v);
		vals[comp[v]].erase(a[v] * n + v);
		comp[v] = compv;
	}
	comp[v] = compv;

	for (pair<int, int> x: edges[v]) {
		if (!rem[x.s] && comp[x.f] != compv) {
			relabel(x.f, compv);
		}
	}
}

void solve(int tc = 0) {
	cin >> n >> m >> q;

	for (int i = 0; i < n; i++) cin >> a[i];

	for (int i = 0; i < m; i++) {
		cin >> ed[i];
		--ed[i].f;
		--ed[i].s;
	}

	memset(rem, 0, sizeof(rem));

	for (int i = 0; i < q; i++) {
		cin >> qv[i];
		--qv[i].s;
		if (qv[i].f == 2) rem[qv[i].s] = 1;
	}

	d.init(n);

	for (int i = 0; i < m; i++) {
		if (!rem[i]) d.merge(ed[i].f, ed[i].s);
	}

	for (int i = q - 1; i >= 0; i--) {
		if (qv[i].f == 2) {
			pair<ll, ll> e = ed[qv[i].s];
			if (d.marks[e.f] == d.marks[e.s]) targ[i].f = -1;
			else {
				if (d.sizes[d.marks[e.f]] > d.sizes[d.marks[e.s]]) swap(e.f, e.s);
				targ[i] = e;
				d.merge(e.f, e.s);
			}
		}
	}

	for (int i = 0; i < n; i++) {
		comp[i] = d.marks[i];

		vals[comp[i]].insert(a[i] * n + i);
	}

	memset(rem, 0, sizeof(rem));

	for (int i = 0; i < m; i++) {
		edges[ed[i].f].push_back(make_pair(ed[i].s, i));
		edges[ed[i].s].push_back(make_pair(ed[i].f, i));
	}

	int comp_val = n;

	for (int i = 0; i < q; i++) {
		if (qv[i].f == 1) {
			if (!vals[comp[qv[i].s]].size()) cout << 0 << '\n';
			else {
				// cout << qv[i].s << " " << comp[qv[i].s] << '\n';
				auto it = --vals[comp[qv[i].s]].end();
				cout << *it / n << '\n';
				a[*it % n] = 0;
				vals[comp[qv[i].s]].erase(it);
			}

			// for (ll i = 0; i < n; i++) cout << comp[i] << " ";
			// cout << '\n';
		} else {
			rem[qv[i].s] = 1;
			if (targ[i].f != -1) {
				kill.clear();
				relabel(targ[i].f, comp_val);
				sort(kill.begin(), kill.end());
				for (ll x: kill) vals[comp_val].insert(vals[comp_val].end(), x);

				++comp_val;
			}
		}
	}
}

int main() {
	#ifdef galen_colin_local
		auto begin = std::chrono::high_resolution_clock::now();
	#endif

	send help

	#ifndef galen_colin_local
		// usaco("moop");
	#endif

	// usaco("cowland");

	// freopen("tc.cpp", "r", stdin);

	int tc = 1;
	// cin >> tc;
	for (int t = 0; t < tc; t++) solve(t);

	#ifdef galen_colin_local
		auto end = std::chrono::high_resolution_clock::now();
		cout << setprecision(4) << fixed;
		// cout << "Execution time: " << std::chrono::duration_cast<std::chrono::duration<double>>(end - begin).count() << " seconds" << endl;
	#endif
}

#include<bits/stdc++.h>
#define P pair<int,int>
using namespace std;
const int N=2e6;
int n,m,q;
int f[N];
int value[N/2];
P edge[N/2];
P ask[N/2];
bool split[N/2];
int l[N/2];
int r[N/2];
P tree[N];
struct nodes
{
    P s;
    P range;
    int f;
}node[N];
int cnt=0,root;
int fa(int);
void link(int,int);
void modify(int L,int R,int p,int x,int val);
P query(int l,int r,int L,int R,int p);
void dfs(int);
int main()
{
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)scanf("%d",&value[i]),f[i]=i;//cin>>value[i],f[i]=i;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        //cin>>u>>v;
        scanf("%d%d",&u,&v);
        edge[i]=P(u,v);
    }
    for(int i=1;i<=n;i++)node[++cnt].range=P(i,i),node[cnt].s=P(0,0);
    for(int i=1;i<=q;i++)
    {
        int a,b;
       // cin>>a>>b;
        scanf("%d%d",&a,&b);
        ask[i]=P(a,b);
        if(a==2)split[b]=true;
    }
    for(int i=1;i<=m;i++)if(!split[i])link(edge[i].first,edge[i].second);
    for(int i=q;i>=1;i--)
    {
        int a,b;
        a=ask[i].first;b=ask[i].second;
        if(a==2)link(edge[b].first,edge[b].second);
        else ask[i].second=fa(b);
    }
    root=cnt;
    cnt=0;
    for(int i=root;i>=1;i--)if(l[i]==0)dfs(i);
  //  for(int i=1;i<=n;i++)cout<<i<<"   : "<<l[i]<<"  -  "<<r[i]<<endl;
 //cout<<"finish dfs\n";
    for(int i=1;i<=n;i++)modify(1,cnt,1,l[i],value[i]);

    for(int i=1;i<=q;i++)
    {
        int a,b;
        a=ask[i].first;b=ask[i].second;
        if(a==2)continue;
      //  cout<<"now ask: "<<b<<endl;
        P ans=query(l[b],r[b],1,cnt,1);
        modify(1,cnt,1,ans.second,0);
      //  cout<<"  ans:  "<<ans.first<<"  pos: "<<ans.second<<endl;
      //  cout<<ans.first<<endl;
      printf("%d\n",ans.first);
    }
}

void dfs(int u)
{
  //  cout<<"in node "<<u;
    cnt++;
    l[u]=cnt;r[u]=cnt;
 //   cout<<"    cnt : "<<cnt<<endl;
    if(node[u].s==P(0,0))return;
    dfs(node[u].s.first);
    dfs(node[u].s.second);
    int v=node[u].s.second;
    r[u]=r[v];
  //  cout<<u<<"  l = "<<l[u]<<"  r = "<<r[u]<<endl;
}

int fa(int x)
{
    if(f[x]==x)return x;
    else return f[x]=fa(f[x]);
}

void link(int u,int v)
{
    u=fa(u);v=fa(v);
    if(u==v)return;
    cnt++;
    f[cnt]=cnt;f[u]=cnt;f[v]=cnt;
    node[cnt].s=P(u,v);
}

P query(int l,int r,int L,int R,int p)
{

    if(l==L&&r==R)return tree[p];
    int mid=(L+R)>>1;
    if(r<=mid)return query(l,r,L,mid,p+p);
    else if(mid+1<=l)return query(l,r,mid+1,R,p+p+1);
    else return max(query(l,mid,L,mid,p+p),query(mid+1,r,mid+1,R,p+p+1));
}

void modify(int L,int R,int p,int x,int val)
{
//cout<<L<<"  "<<R<<"  x: "<<x<<endl;
    if(L==R&&L==x)
    {
        tree[p]=P(val,L);
        return;
    }
    int mid=(L+R)>>1;
    if(x<=mid)modify(L,mid,p+p,x,val);
    else modify(mid+1,R,p+p+1,x,val);
    tree[p]=max(tree[p+p],tree[p+p+1]);
}

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define isz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
using li = std::list<int>;
using vi = std::vector<int>;
using vli = std::vector<li>;
using pii = std::pair<int,int>;
using vpii = std::vector<pii>;

namespace FastIO {
    struct Reader {
    private:
        FILE* file; std::vector<char> buffer; int pos; bool was;
        void read() {
            if (!buffer.empty()) {
                buffer.resize(fread(&buffer[0], 1, (int)buffer.size(), file)); pos = 0;
            }
        }
    public:
        Reader(FILE* file_ = stdin, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(size_), was(true) { }
        operator bool() const { return was; }
        char getChar() {
            if (pos == (int)buffer.size()) { read(); }
            if (pos == (int)buffer.size()) { was = false; return EOF; }
            else { was = true; return buffer[pos++]; }
        }
        std::string getStr() {
            char c = ' ';
            while (std::isspace(c)) { c = getChar(); }
            std::string answ;
            while (c != EOF && !std::isspace(c)) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        std::string getLine() {
            char c = '\n';
            while (c == '\n') { c = getChar(); }
            std::string answ;
            while (c != '\n' && c != EOF) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        template<typename T> T getInt() {
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = true;
            if (c == '-') { positive = false; c = getChar(); }
            T answ(0);
            bool flag = false;
            while ('0' <= c && c <= '9') { flag = true; (answ *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            return positive ? answ : -answ;
        }
        template<typename T> T getReal() {
            bool flag = false;
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = (c != '-');
            if (c == '-') { c = getChar(); }
            long long first = 0;
            while ('0' <= c && c <= '9') { flag = true; (first *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            if (c != '.') { return T(positive ? first : -first); }
            c = getChar();
            long long second = 0, pow = 1;
            while ('0' <= c && c <= '9') { (second *= 10) += (c - '0'); c = getChar(); pow *= 10; }
            T answ = first + (T)second / (T)pow;
            return positive ? answ : -answ;
        }
    };

    Reader& operator>>(Reader& reader, char& c) { return c = reader.getChar(), reader; }

    Reader& operator>>(Reader& reader, std::string& s) { return s = reader.getStr(), reader; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getReal<T>(), reader; }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getInt<T>(), reader; }

    template<class T> Reader& operator>>(Reader& reader, std::vector<T>& vec) {
        for (auto &it : vec) { reader >> it; }
        return reader;
    }

    struct Writer {
    private:
        FILE* file; std::vector<char> buffer; int pos;
        int defaultPrecision, defaultWidth; char defaultFill;
    public:
        Writer(FILE* file_ = stdout, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(0), defaultPrecision(6), defaultWidth(0), defaultFill(' ') { }
        ~Writer() { flush(); }
        void flush() { putChar(EOF); }
        void setprecision(int precision) { defaultPrecision = precision; }
        void setw(int width) { defaultWidth = width; }
        void setfill(char fill) { defaultFill = fill; }
        int getPrecision() const { return defaultPrecision; }
        int getWidth() const { return defaultWidth; }
        char getFill() const { return defaultFill; }
        void putChar(char c) {
            if (pos == (int)buffer.size() || c == EOF) {
                fwrite(&buffer[0], 1, pos, file); pos = 0;
            }
            if (c != EOF) { buffer[pos++] = c; }
        }
        void putStr(const std::string& s) { for (auto it : s) putChar(it); }
        template<typename T> void putInt(T value, int width = 0, char fill = ' ') {
            bool positive = !(value < 0);
            if (value < 0) { value = -value; }
            char buf[24]; int p = 0;
            do { buf[p++] = char(value % 10 + '0'); value /= 10; } while (value > 0);
            if (!positive) { buf[p++] = '-'; }
            while (p < width) buf[p++] = fill;
            while (p > 0) putChar(buf[--p]);
        }
        template<typename T> void putReal(T value, int precision = 6, int width = 0, char fill = ' ') {
            putInt((long long)value, width - precision - 1, fill);
            value = std::abs(value-(long long)value);
            if (precision == 0) { return; }
            putChar('.');
            #define PRINT_PART(cnt, pow) \
                while (precision >= cnt) { \
                    value *= pow; \
                    putInt((int)value, cnt, '0'); \
                    value -= (int)value; \
                    precision -= cnt; \
                }
            PRINT_PART(6,1000000)
            PRINT_PART(3,1000)
            PRINT_PART(1,10)
            #undef PRINT_PART
        }
    };

    Writer& operator<<(Writer& writer, const char c) { return writer.putChar(c), writer; }

    Writer& operator<<(Writer& writer, const std::string& s) { return writer.putStr(s), writer; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putReal(t, writer.getPrecision(), writer.getWidth(), writer.getFill());
        return writer;
    }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putInt(t, writer.getWidth(), writer.getFill());
        return writer;
    }
}

struct DSUList {
    vi par;
    vli data;
    DSUList(int n) : par(n,0),data(n,{0}) {
        for (int i = 0; i < n; i++) par[i] = i, data[i] = {i};
    }
    int getParent(int u) {
        return par[u] == u ? u : par[u] = getParent(par[u]);
    }
    void connect(int u, int v) {
        u = getParent(u);
        v = getParent(v);
        if (u == v) return;
        if (isz(data[u]) <= isz(data[v])) {
            data[v].insert(data[v].begin(),all(data[u]));
            par[u] = v;
            data[u].clear();
        } else {
            data[u].insert(data[u].end(),all(data[v]));
            par[v] = u;
            data[v].clear();
        }
    }
};
struct DSUSegs {
    vi par,start,end,sz;
    DSUSegs(int n) : par(n,0),start(n,0),end(n,0),sz(n,1) {
        for (int i = 0; i < n; i++) par[i] = i;
        // надеюсь кто-нибудь проинициализирует start извне
    }
    int getParent(int u) {
        return par[u] == u ? u : par[u] = getParent(par[u]);
    }
    int connect(int u, int v) {
        u = getParent(u);
        v = getParent(v);
        if (u == v) return isz(par);
        int lu = start[u];
        int ru = end[u];
        int lv = start[v];
        int rv = end[v];
        assert(ru == lv || rv == lu);
        if (sz[u] < sz[v]) std::swap(u,v);
        assert(sz[u] >= sz[v]);
        par[v] = u;
        sz[u] += sz[v];
        int delim = std::max(lu,lv);
        start[u] = std::min(lu,lv);
        end[u] = std::max(ru,rv);
        return delim;
    }
};
pii merge(pii a, pii b) {
    if (a.first >= b.first) return a;
    else return b;
}
struct SegTree {
    vpii data;
    SegTree(const vi& arr) : data(4 * isz(arr), pii{-1,-1}) { build(0,0,isz(arr),arr); }
    void build(int v, int l, int r, const vi& arr) {
        if (l + 1 == r) {
            data[v] = {arr[l],l};
        } else {
            int m = (l + r) / 2;
            build(2*v+1,l,m,arr);
            build(2*v+2,m,r,arr);
            data[v] = merge(data[2*v+1], data[2*v+2]);
        }
    }
    pii get(int v, int l, int r, int ql, int qr) {
        if (qr <= l || r <= ql) return pii(-1,-1);
        if (ql <= l && r <= qr) return data[v];
        int m = (l+r)/2;
        return merge(get(2*v+1,l,m,ql,qr),get(2*v+2,m,r,ql,qr));
    }
    void set(int v, int l, int r, int p, int x) {
        if (p < l || p >= r) return;
        if (l + 1 == r) {
            data[v] = {x,p};
        } else {
            int m = (l+r)/2;
            set(2*v+1,l,m,p,x);
            set(2*v+2,m,r,p,x);
            data[v] = merge(data[2*v+1], data[2*v+2]);
        }
    }
};

vi solve(const int nV, const int nE, const int nQ, vi number, vpii edges, vpii queries) {
    assert(nQ == isz(queries));
    vi willBeRemoved(nE);
    for (auto &[fi,se] : queries) {
        if (fi == 2) willBeRemoved[se] = 1;
    }
    for (int i = 0; i < nE; i++) {
        if (!willBeRemoved[i]) queries.emplace_back(2,i);
    }
    // надо найти порядок вершин который позволит при удалении ребра разбивать компоненту
    // на два непрерывных отрезка
    std::reverse(all(queries));
    DSUList dsuList(nV);
    for (auto &[fi,se] : queries) {
        if (fi == 2) {
            auto &[u,v] = edges[se];
            dsuList.connect(u,v);
        }
    }
    // вроде dsu все соединило в нужном порядке, сливаем компоненты в массив
    std::set<int> start{nV};
    vi order;
    for (int u = 0; u < nV; u++) {
        int p = dsuList.getParent(u);
        start.insert(isz(order));
        order.insert(order.end(), all(dsuList.data[p]));
        dsuList.data[p].clear();
    }
    assert(isz(order) == nV);
    vi pos(nV);
    for (int i = 0; i < nV; i++) pos[order[i]] = i;
    // вроде готово
    // надо понять как запросы будут делить непрерывные отрезки на две части
    DSUSegs dsuSegs(nV);
    for (int u = 0; u < nV; u++) {
        dsuSegs.start[u] = pos[u];
        dsuSegs.end[u] = pos[u]+1;
    }
    vi delimiters;
    for (auto &[fi,se] : queries) {
        if (fi == 2) {
            auto &[u,v] = edges[se];
            int mid = dsuSegs.connect(u,v);
            delimiters.push_back(mid);
        }
    }
    // готовы отвечать на запросы
    std::reverse(all(queries));
    vi arr(nV);
    for (int u = 0; u < nV; u++) arr[pos[u]] = number[u];
    SegTree st(arr);
    vi answer;
    for (auto &[fi,se] : queries) {
        if (fi == 1) {
            int u = se;
            auto r = start.upper_bound(pos[u]);
            assert(r != start.begin());
            auto l = std::prev(r);
            pii answ = st.get(0,0,nV,*l,*r);
            answer.push_back(answ.first);
            st.set(0,0,nV,answ.second,0);
        } else {
            start.insert(delimiters.back());
            delimiters.pop_back();
        }
    }
    return answer;
}

FastIO::Reader cin;
FastIO::Writer cout;

void readTest(int &nV, int &nE, int &nQ, vi& number, vpii& edges, vpii& queries) {
    cin >> nV >> nE >> nQ;
    number.resize(nV); for (auto & it : number) cin >> it;
    edges.resize(nE);
    for (auto &[u,v]: edges) cin >> u >> v,u--,v--;
    queries.resize(nQ);
    for (auto &[fi,se] : queries) {
        cin >> fi >> se;
        se--;
    }
    // наконец-то прочитали все данные!
}

int main() {
    int nV,nE,nQ;
    vi number;
    vpii edges, queries;
    readTest(nV,nE,nQ,number,edges,queries);
    auto answ = solve(nV,nE,nQ,number,edges,queries);
    for (auto it : answ) cout << it << '\n';
    return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
#pragma GCC optimize("unroll-loops")

#pragma GCC optimize("O3")
#pragma GCC optimize("O2")
#pragma GCC optimize("Og")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
// #include <bits/stdc++.h>
#include <complex>
#include <queue>
#include <set>
#include <unordered_set>
#include <list>
#include <chrono>
#include <random>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <stack>
#include <iomanip>
#include <fstream>
#include <functional> // for less
#include <iostream>
using namespace std;

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> p32;
typedef pair<ll, ll> p64;
typedef pair<double, double> pdd;
typedef vector<ll> v64;
typedef vector<int> v32;
typedef vector<vector<int>> vv32;
typedef vector<vector<ll>> vv64;
#define vvv64 vector<vv64>
#define vvvv64 vector<vvv64>

typedef vector<vector<p64>> vvp64;
typedef vector<p64> vp64;
typedef vector<p32> vp32;
ll MOD = 998245709;
#define forn(i, e) for (ll i = 0; i < e; i++)
#define forsn(i, s, e) for (ll i = s; i < e; i++)
#define rforn(i, s) for (ll i = s; i >= 0; i--)
#define rforsn(i, s, e) for (ll i = s; i >= e; i--)
#define ln "\n"
#define dbg(x) cout << #x << " = " << x << ln
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define INF 1e18
#define fast_cin()                    \
    ios_base::sync_with_stdio(false); \
    cin.tie(NULL);                    \
    cout.tie(NULL)
#define all(x) (x).begin(), (x).end()
#define sz(x) ((ll)(x).size())
#define vc vector<char>
#define vvc vector<vc>
#define pp pair<p64, ll>
ll exp(ll n, ll e)
{
    if (e == 0)
        return 1;
    ll temp = exp((n * n) % MOD, e / 2);
    return e % 2 == 0 ? temp : (temp * n) % MOD;
}
ll inverse(ll n)
{
    return exp(n, MOD - 2);
}
void frac(ll p, ll q)
{
    cout << (p * inverse(q)) % MOD << endl;
}

ll ceil_div(ll a, ll b)
{
    return (a + b - 1) / b;
}

const int LIM = 2e5 + 5;
const int LIM2 = 5e5 + 5;
int value[LIM];
int par1[LIM2], par2[LIM2];
// set<p32> rem2[LIM2];
vector<v32> rem3(LIM2);
class UnionFind
{
public:
    v32 p, sz;
    vector<set<p32>> elements;
    void init(int N)
    {
        elements = vector<set<p32>>(N);
        p.assign(N, 0);
        sz.assign(N, 1);
        forn(i, N)
        {
            p[i] = i;
            elements[i].insert({value[i], i});
        }
    }
    int findSet(ll i)
    { // returns the head of group containing element i
        return (p[i] == i) ? i : findSet(p[i]);
    }
    void answer(int x)
    {
        int a = findSet(x);
        auto it = *elements[a].rbegin();
        cout << it.first << '\n';
        elements[a].erase(it);
        elements[a].insert({0, it.se});
        value[it.se] = 0;
    }
    void unionSet(int i, int j, int k)
    { // unify group containing i and j(if already in same set then do nothing)
        int x = findSet(i), y = findSet(j);
        if (x != y)
        {
            if (sz[x] > sz[y])
                swap(x, y);
            if (k >= 0)
            {
                par1[k] = x;
                par2[k] = y;
            }
            p[x] = y;
            sz[y] += sz[x];
            for (auto &it : elements[x])
            {
                elements[y].insert(it);
                if (k >= 0)
                {
                    // rem2[k].insert(it);
                    rem3[k].push_back(it.se);
                }
            }
            elements[x].clear();
        }
    }
    int sz1(int i)
    {
        return sz[i];
    }
};
int query1[LIM2], query2[LIM2];
const int LIM3 = 3e5 + 5;
bool remov[LIM3];
int u[LIM3], v[LIM3];
UnionFind dsu;
void solve()
{
    //Read Comments below main
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        cin >> value[i];
    // UnionFind dsu(n + 1);
    dsu.init(n + 1);
    for (int i = 1; i <= m; i++)
    {
        int a, b;
        cin >> u[i] >> v[i];
    }
    for (int i = 0; i < q; i++)
    {
        int op, x;
        cin >> op >> x;
        if (op == 2)
            remov[x] = 1;
        query1[i] = op;
        query2[i] = x;
    }
    for (int i = 1; i <= m; i++)
    {
        if (remov[i] == 0)
        {
            dsu.unionSet(u[i], v[i], -1);
        }
    }
    for (int i = q - 1; i >= 0; i--)
    {
        int op = query1[i];
        int x = query2[i];
        if (op == 2)
        {
            dsu.unionSet(u[x], v[x], i);
        }
    }
    for (int i = 0; i < q; i++)
    {
        if (query1[i] == 1)
        {
            dsu.answer(query2[i]);
        }
        else
        {
            int p1 = par1[i];
            int p2 = par2[i];
            dsu.p[p1] = p1;
            // for (auto &it : rem2[i])
            for (auto &it : rem3[i])
            {
                dsu.elements[p2].erase({value[it], it});
                dsu.elements[p1].insert({value[it], it});
            }
            // rem2[i].clear();
            rem3[i].clear();
        }
    }
}

int32_t main()
{
    fast_cin();
    ll t = 1;
    // cin >> t;
    for (ll i = 1; i <= t; i++)
    {
        solve();
    }
    return 0;
}
// BITMASK:
// 1)When some constrall is of the order of 15-20, think of bitmask DP.
// 2)When some constrall is around 40, try out meet in the middle
// 3) See Strings,palindromes,prefix,suffix etc -> KMP,Z algorithm

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <bits/stdc++.h>

using namespace std;

#define POW2(X) (1<<(X))
#define CKBIT(S,X) (((S)&POW2(X))!=0)
const double pi=acos(-1.0);
const double eps=1e-11;
template<class T> inline void ckmin(T &a,T b){ a=min(a,b); }
template<class T> inline void ckmax(T &a,T b){ a=max(a,b); }
template<class T> inline T sqr(T x){ return x*x; }
#define SIZE(A) ((int)A.size())
#define LENGTH(A) ((int)A.length())
#define MP(A,B) make_pair(A,B)
#define PB(X) push_back(X)
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,a) for(int i=0;i<(a);++i)
#define ALL(A) A.begin(),A.end()
using uint=unsigned int;
using int64=long long;
using uint64=unsigned long long;
using ipair=pair<int,int>;
using VI=vector<int>;
using VD=vector<double>;

class UnionFind {
 public:
  UnionFind(int n) {
	  groups_ = std::vector<int>(n, -1);
  }

  int Find(int p) {
	  int r = p;
	  while (groups_[r] >= 0) r = groups_[r];
	  int t = groups_[p];
	  while (t >= 0) {
		groups_[p] = r;
		p = t;
		t = groups_[p];
	  }
	  return r;
  }

  std::vector<int> groups_;
};

struct Query
{
    int tp;
    int key;
    int ret;
};
struct Edge
{
    int u;
    int v;
};

struct Range
{
	int s = 0;
	int t = -1;
	Range() = default;
	Range(int s, int t) : s(s), t(t) { }

	int size() const { return t - s + 1; }
	bool has_overlap(const Range& other_range) const { return s <= other_range.t && t >= other_range.s; }
	bool is_contain(const Range& other_range) const { return s <= other_range.s && t >= other_range.t; }
};

struct Node
{
	Range range;
	Node* left_child;
	Node* right_child;

	// Data
	ipair max_val;

	void init(Range _range)
	{
		range = _range;
		max_val = MP(0, range.s);
	}
	void pop()
	{
		if (range.s == range.t) { assert(left_child == nullptr && right_child == nullptr); return; }
		assert(left_child != nullptr && right_child != nullptr);
		const Node& l = *left_child;
		const Node& r = *right_child;
		max_val = max(l.max_val, r.max_val);
	}
	void push()
	{
	}

	int size() const { return range.size(); }
	int mid() const { return (range.s + range.t) / 2; }
};

class IntervalTree
{
public:
	void build(int min_idx, int max_idx)
	{
		assert(min_idx <= max_idx);
		int size = max_idx - min_idx + 1;
		for (; size & (size - 1); size += (size & (-size)));
		reset_buffer(size * 2);
		root = build_internal(min_idx, max_idx);
	}

	template<class Func>
	void traverse(const Range& range, Func func)
	{
		traverse_internal(range, func, 0);
	}

	template<class Func>
	void traverse_in_reverse_order(const Range& range, Func func)
	{
		traverse_internal(range, func, 1);
	}

	Node* root;

private:
	template<class Func>
	void traverse_internal(const Range& range, Func func, int reverse_order)
	{
		assert(root != nullptr);
		if (!range.has_overlap(root->range)) return;
		traverse_nodes_internal(root, range, func, reverse_order);
	}

	template<class Func>
	void traverse_nodes_internal(Node* p, const Range& range, Func func, int reverse_order)
	{
		if (range.is_contain(p->range)) { func(p); return; }
		p->push();
		int m = p->mid();
		if (reverse_order)
		{
			if (m < range.t) traverse_nodes_internal(p->right_child, range, func, reverse_order);
			if (m >= range.s) traverse_nodes_internal(p->left_child, range, func, reverse_order);
		}
		else
		{
			if (m >= range.s) traverse_nodes_internal(p->left_child, range, func, reverse_order);
			if (m < range.t) traverse_nodes_internal(p->right_child, range, func, reverse_order);
		}
		p->pop();
	}

	Node* build_internal(int min_idx, int max_idx)
	{
		assert(buffer_pos < buffer.size());
		Node* p = &buffer[buffer_pos++];
		p->init(Range(min_idx, max_idx));
		if (min_idx == max_idx)
			p->left_child = p->right_child = nullptr;
		else
		{
			int m = (min_idx + max_idx) / 2;
			p->left_child = build_internal(min_idx, m);
			p->right_child = build_internal(m + 1, max_idx);
			p->pop();
		}
		return p;
	}

	void reset_buffer(int size)
	{
		buffer_pos = 0;
		buffer.clear();
		buffer.resize(size);
	}

	vector<Node> buffer;
	int buffer_pos;
};

int main()
{
#ifdef _MSC_VER
	freopen("input.txt","r",stdin);
#endif
	std::ios::sync_with_stdio(false);
    int n,m,nq;
    cin>>n>>m>>nq;
    VI val(n+m);
    REP(i,n) cin>>val[i];
    vector<Edge> e(m);
    REP(i,m) { cin>>e[i].u>>e[i].v; --e[i].u; --e[i].v; }
    vector<Query> q(nq);
    REP(i,nq) { cin>>q[i].tp>>q[i].key; --q[i].key; }
    VI deleted(m);
    REP(i,nq) if (q[i].tp==2) deleted[q[i].key]=1;
    UnionFind uf(n+m);
    int next_id=n;
    vector<VI> g(n+m);
    auto add=[&](int a,int b) {
        a=uf.Find(a);
        b=uf.Find(b);
        if (a==b) return;
        int c=(next_id++);
        uf.groups_[a]=uf.groups_[b]=c;
        g[c].push_back(a);
        g[c].push_back(b);
    };
    REP(i,m) if (!deleted[i]) add(e[i].u,e[i].v);
    for (int i=nq-1;i>=0;i--)
        if (q[i].tp==2)
            add(e[q[i].key].u,e[q[i].key].v);
        else
            q[i].key=uf.Find(q[i].key);
    VI que;
    VI idx(n+m,-1);
    VI last(n+m);
    std::function<void(int)> dfs=[&](int p) {
        idx[p]=SIZE(que);
        que.push_back(p);
        for (int x:g[p]) dfs(x);
        last[p]=SIZE(que)-1;
    };
	VI indeg(n+m);
	REP(i,n+m) for (int j:g[i]) ++indeg[j];
    REP(i,n+m) if (indeg[i]==0) dfs(i);
    VI a(n+m);
    REP(i,SIZE(que)) a[i]=val[que[i]];

	IntervalTree tree;
	tree.build(0,n+m-1);
	auto update=[&](int at,int val) {
		a[at]=val;
		tree.traverse(Range(at,at),[&](Node* node) { if (node->range.size()==1) node->max_val=MP(val,at); });
	};
	REP(i,n+m) update(i,a[i]);

    REP(k,nq)
        if (q[k].tp==1)
        {
            int s=idx[q[k].key];
            int t=last[q[k].key];
			ipair ret=MP(-1,-1);
			tree.traverse(Range(s,t),[&](Node* node) { ret=max(ret,node->max_val); });
			printf("%d\n",ret.first);
			int key=ret.second;
			update(key,0);
			/*
            int key=-1;
            FOR(i,s,t+1) if (key<0 || a[i]>a[key]) key=i;
            printf("%d\n",a[key]);
            a[key]=0;
			*/
        }
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<double> vd;
typedef vector<string> vs;
typedef vector<pii> vii;
typedef vector<pll> vll;
typedef vector<pdd> vdd;
typedef vector<vl> vvl;
typedef vector<vd> vvd;
const int mod = 1000000007;
const vi mods = {998244353,1000000007,1000000009};
const ll inf = 3e18;
const double pi = acos(-1.0);
const double eps = 0.0000001;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define rep(i,a,b) for(ll i=(a);i<(b);++i)
#define trav(a,x) for(auto&a:x)
#define all(x) begin(x),end(x)
#define sz(x) ((int)(x).size())
#define fll(xs,x,a) fill(&x,&x+sizeof(xs)/sizeof(x)-1,a)//fll(dp,dp[0][0],inf)
#define has(x,a) (x.find(a)!=end(x))
#define pc(x) __builtin_popcountll(x)
#define pb push_back
#define fi first
#define se second
template<class...K> using umap = unordered_map<K...>;
template<class...K> using uset = unordered_set<K...>;

const int N=500100;
int n,m,q,u,v,ty,x,p[N],par[N],siz[N];
umap<int,set<pii>>mns;
umap<int,vi>g;
int egs[N][3],qs[N][2];
uset<int>lt;

void build(){
  rep(i,0,n){
    mns[i].insert({p[i],i});
    par[i]=i;
    siz[i]=1;
  }
}

inline int fnd(int x){
  return par[x]==x?x:fnd(par[x]);
}

bool unn(int e){
  int x=egs[e][0],y=egs[e][1];
  int rx=fnd(x),ry=fnd(y);
  if(rx==ry)return 0;
  if(siz[rx]<siz[ry])swap(rx,ry);
  siz[rx]+=siz[ry];
  par[ry]=rx;
  g[rx].pb(ry);
  egs[e][2]=ry;
  trav(mny,mns[ry])mns[rx].insert(mny);
  mns[ry].clear();
  return 1;
}

void dfs(int x,int rm,int ad){
  if(p[x]){
    pll mn={p[x],x};
    mns[rm].erase(mns[rm].find(mn));
    mns[ad].insert(mn);
  }
  trav(nx,g[x])dfs(nx,rm,ad);
}

bool splt(int e){
  if(egs[e][2]==-1)return 0;
  int ry=egs[e][2];
  int rx=fnd(ry);
  g[par[ry]].pop_back();
  par[ry]=ry;
  dfs(ry,rx,ry);
  return 1;
}

int getmn(int x){
  int rx=fnd(x);
  if(!sz(mns[rx]))return 0;
  auto pp=--end(mns[rx]);
  p[pp->se]=0;
  int mn=pp->fi;
  mns[rx].erase(pp);
  return mn;
}

int main() {
  cin.sync_with_stdio(0);
  cin.tie(0);
  cout.precision(13);

  cin>>n>>m>>q;
  rep(i,0,n)cin>>p[i];
  build();
  rep(i,0,m){
    cin>>u>>v;
    u--;v--;
    egs[i][0]=u,egs[i][1]=v,egs[i][2]=-1;
  }
  rep(_q,0,q){
    cin>>ty>>x;
    x--;
    qs[_q][0]=ty,qs[_q][1]=x;
    if(ty==2)lt.insert(x);
  }
  rep(i,0,m){
    if(has(lt,i))continue;
    unn(i);
  }
  for(int _q=q-1;_q>=0;_q--){
    ty=qs[_q][0],x=qs[_q][1];
    if(ty!=2)continue;
    unn(x);
  }
  rep(_q,0,q){
    ty=qs[_q][0],x=qs[_q][1];
    if(ty==1)cout<<getmn(x)<<"\n";
    else splt(x);
  }

  return 0;
}

#include <bits/stdc++.h>
/** #include <ext/pb_ds/assoc_container.hpp>
 * #include <ext/pb_ds/tree_policy.hpp>
 * using namespace __gnu_pbds; */
using namespace std;

#define ll long long
#define ull unsigned long long
#define f(a, b) for (ll i = a; i < b; i++)
#define mod 1000000007
#define pb push_back
#define vll vector<ll>
#define pll vector<pair<ll, ll>>
#define ld long double
#define fr(a, b) for (ll j = a; j >= b; j--)
#define fi(a, b) for (ll j = a; j < b; j++)
#define fii(a, b) for (ll k = a; k < b; k++)
/** typedef tree<ll
 * ,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>
 * ordered_set; */

template <class T> ostream &operator<<(ostream &os, vector<T> V) {
  os << "[ ";
  for (auto v : V)
    os << v << " ";
  os << "]";
  return os;
}
template <class T> ostream &operator<<(ostream &os, set<T> S) {
  os << "{ ";
  for (auto s : S)
    os << s << " ";
  return os << "}";
}
template <class L, class R> ostream &operator<<(ostream &os, map<L, R> M) {
  os << "{ ";
  for (auto m : M)
    os << "(" << m.first << ":" << m.second << ") ";
  return os << "}";
}
template <class L, class R> ostream &operator<<(ostream &os, pair<L, R> P) {
  return os << "(" << P.first << "," << P.second << ")";
}

const ll N = 200005;
ll p[N];
ll x[N << 1], y[N << 1];
bool removed[N << 1];
pll query;

struct DSU {

  vector<ll> a, s;
  pll changes;
  vector<set<ll>> elements;

  DSU(ll n) {
    a.resize(n + 1);
    s.resize(n + 1);
    elements.resize(n + 1);
    for (int i = 1; i <= n; i++) {
      a[i] = i;
      s[i] = 1;
      elements[i].insert(p[i]);
    }
  }

  ll root(ll i) {
    while (i != a[i]) {
      // a[i] = a[a[i]];
      i = a[i];
    }
    return i;
  }

  bool merge(ll x, ll y) {
    ll xr = root(x), yr = root(y);
    if (xr == yr) {
      changes.pb({xr, xr});
      return false;
    }
    if (s[xr] < s[yr])
      swap(xr, yr);
    s[xr] += s[yr];
    elements[xr].insert(elements[yr].begin(), elements[yr].end());
    a[yr] = xr;
    changes.pb({xr, yr});
    return true;
  }

  void rollBack() {
    if (changes.empty())
      return;
    pair<ll, ll> p = changes.back();
    ll xr = p.first, yr = p.second;
    changes.pop_back();
    if (xr == yr)
      return;
    for (auto it = elements[yr].begin(); it != elements[yr].end();) {
      if (elements[xr].find(*it) != elements[xr].end())
        elements[xr].erase(*it), it++;
      else
        it = elements[yr].erase(it);
    }
    a[yr] = yr;
    s[xr] = elements[xr].size();
    s[yr] = elements[yr].size();
  }

  ll query(ll x) {
    ll xr = root(x);
    if (elements[xr].empty())
      return 0;
    ll ret = *(--elements[xr].end());
    elements[xr].erase(--elements[xr].end());
    s[xr]--;
    return ret;
  }
};

int main() {
#ifndef ONLINE_JUDGE
  freopen("input.txt", "rt", stdin);
  freopen("output.txt", "wt", stdout);
#endif
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  set<ll> s;
  s.erase(5);
  ll n, m, q;
  cin >> n >> m >> q;
  f(1, n + 1) cin >> p[i];
  f(1, m + 1) cin >> x[i] >> y[i];
  query.resize(q);
  vll r;
  f(0, q) {
    cin >> query[i].first >> query[i].second;
    if (query[i].first == 2)
      removed[query[i].second] = true, r.pb(query[i].second);
  }
  DSU d(n);
  f(1, m + 1) {
    if (!removed[i])
      d.merge(x[i], y[i]);
  }
  reverse(r.begin(), r.end());
  f(0, r.size()) d.merge(x[r[i]], y[r[i]]);
  f(0, q) {
    if (query[i].first == 1)
      cout << d.query(query[i].second) << '\n';
    else
      d.rollBack();
  }

#ifndef ONLINE_JUDGE
  cout << "\nTime Elapsed : " << 1000 * (ld)clock() / (ld)CLOCKS_PER_SEC
       << " ms\n";
#endif
  return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define f first
#define s second
using namespace std;
const int mxn=2e5+5;
const int mxm=3e5+5;
const int mxq=5e5+5;

const int inf=1e9;
int p[mxn];
int L[mxm],R[mxm];
bool usd[mxm];
int tp[mxq],id[mxq];

struct reachability_tree {
	int parent[mxn];
	int sz[mxn];
	int in[mxn],out[mxn],id[mxn];
	int pc[mxn];
	vector<int> g[mxn];
	vector<int> w[mxn];
	int T=0;

	void init(int n) {
		for(int i=1;i<=n;i++) {
			parent[i] = i;
			sz[i] = 1;
		}
	}

	int findrep(int u) {
		return parent[u] == u ? u : findrep(parent[u]);
	}

	void unite(int u,int v,int cst) {
		u=findrep(u);
		v=findrep(v);
		if(u == v) return;

		if(sz[u] > sz[v]) swap(u,v);

		parent[u] = v;
		sz[v] += sz[u];
		g[v].push_back(u);
		w[v].push_back(cst);
		pc[u] = cst;

	}
	void dfs(int u) {
		in[u] = ++T;
		id[T] = u;
		for(int v : g[u]) {
			dfs(v);
		}
		out[u] = T;
	}

	pii range(int u, int tm) {
		while(parent[u] != u && pc[u] >= tm) u = parent[u];

		int p = upper_bound(w[u].begin(),w[u].end(),tm,[](int a,int b) {
			return a > b;
		}) - w[u].begin();

		if(p == 0) {
			return {in[u], in[u]};
		}

		int v = g[u][p-1];
		return {in[u],out[v]};
	}

} rt ;

struct segtree {
	pii tree[4*mxn];

	void update(int node,int b,int e,int p,int v) {
		if(e<p || b>p) return;
		if(b == e) {
			tree[node] = {v,b};
			return;
		}

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		update(left,b,mid,p,v);
		update(right,mid+1,e,p,v);
		tree[node]=max(tree[left],tree[right]);
	}

	pii query(int node,int b,int e,int l,int r) {
		if(b > r || e < l) return {0,0};

		if(b >=l && e <=r ) return tree[node];

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		return max(query(left,b,mid,l,r) , query(right,mid+1,e,l,r));

	}
} st;

int main() {
	int n,m,q;
	cin>>n>>m>>q;

	for(int i=1;i<=n;i++) {
		scanf("%d",&p[i]);
	}

	for(int i=1;i<=m;i++) {
		scanf("%d%d",&L[i], &R[i]);
	}

	for(int i=1;i<=q;i++) {
		scanf("%d %d", &tp[i], &id[i]);

		if(tp[i]==2) usd[id[i]] = true;
	}
	rt.init(n);

	for(int i=1;i<=m;i++) {
		if(!usd[i]) rt.unite(L[i],R[i],inf);
	}

	for(int i=q;i>0;i--) {
		if(tp[i] == 2) rt.unite(L[id[i]],R[id[i]],i);
	}

	for(int i=1;i<=n;i++) {
	    if(rt.findrep(i) == i) {
	        rt.dfs(i);
	    }
	}

	for(int i=1;i<=n;i++) {
		st.update(1,1,n,rt.in[i],p[i]);
	}
	bool dn[mxn]={};

	for(int i=1;i<=q;i++) {
		if(tp[i] == 1) {
			pii rg= rt.range(id[i],i);
			pii x = st.query(1,1,n,rg.f,rg.s);

			if(x.f == 0) {
				printf("0\n");
			} else {
				printf("%d\n", x.f);
				if(dn[x.s]) continue;
				st.update(1,1,n,x.s,0);
			}
		}
	}

}

#include<bits/stdc++.h>

#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
#define debug(x) cerr << #x << " = " << x << endl;

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = (int)5e5 + 5;
const int MAXM = (int)3e5 + 5;
const int MAXQ = (int)5e5 + 5;

pii e[MAXM], que[MAXQ], t[MAXN << 2];
vector<int> adj[MAXN];
int tin[MAXN], tout[MAXN], timer;
int par[MAXN], arr[MAXN];
bool del[MAXM];
int n, m, q;

int getPar(int x) {
  if (x == par[x]) {
    return x;
  }

  return par[x] = getPar(par[x]);
}

void uni(int a, int b) {
  a = getPar(a);
  b = getPar(b);

  if (a == b) {
    return;
  }

  ++n;
  par[n] = n;
  par[a] = n;
  par[b] = n;
  adj[n].pb(a);
  adj[n].pb(b);
}

void dfs(int v) {
  tin[v] = ++timer;

  for (int to : adj[v]) {
    dfs(to);
  }

  tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
  if (l > r || tl > r || tr < l) {
    return mp(0, 0);
  }

  if (l <= tl && tr <= r) {
    return t[v];
  }

  int mid = (tl + tr) >> 1;
  int c1 = (v << 1), c2 = (c1 | 1);

  return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void updPos(int v, int tl, int tr, int p, pii x) {
  if (tl == tr) {
    t[v] = x;
    return;
  }

  int mid = (tl + tr) >> 1;
  int c1 = (v << 1), c2 = (c1 | 1);

  if (p <= mid) {
    updPos(c1, tl, mid, p, x);
  }
  else {
    updPos(c2, mid + 1, tr, p, x);
  }

  t[v] = max(t[c1], t[c2]);
}

void solve() {
  scanf("%d %d %d", &n, &m, &q);

  for (int i = 1; i <= n; ++i) {
    scanf("%d", &arr[i]);
  }

  for (int i = 1; i <= m; ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    e[i] = mp(u, v);
  }

  for (int i = 1; i <= q; ++i) {
    int a, b;
    scanf("%d %d", &a, &b);
    que[i] = mp(a, b);

    if (a == 2) {
      del[b] = 1;
    }
  }

  for (int i = 1; i <= n; ++i) {
    par[i] = i;
  }

  for (int i = 1; i <= m; ++i) {
    if (!del[i]) {
      uni(e[i].fi, e[i].se);
    }
  }

  for (int i = q; i > 0; --i) {
    int tp = que[i].fi;

    if (tp == 2) {
      int id = que[i].se;
      uni(e[id].fi, e[id].se);
    }
    else {
      que[i].se = getPar(que[i].se);
    }
  }

  for (int i = 1; i <= n; ++i) {
    if (getPar(i) == i) {
      dfs(i);
    }
  }

  for (int i = 1; i <= n; ++i) {
    updPos(1, 1, n, tin[i], mp(arr[i], tin[i]));
  }

  for (int i = 1; i <= q; ++i) {
    int tp = que[i].fi;

    if (tp == 1) {
      int v = que[i].se;
      pii tmp = segMax(1, 1, n, tin[v], tout[v]);

      if (tmp.fi == 0) {
        printf("0\n");
      }
      else {
        printf("%d\n", tmp.fi);
        updPos(1, 1, n, tmp.se, mp(0, 0));
      }
    }
  }
}

int main() {
  int tt = 1;

  while (tt--) {
    solve();
  }

  return 0;
}

#include <bits/stdc++.h>
using namespace std;
int sz[800005];
int par[800005];
int p[800005];
inline int fn(int x){
	if(par[x] == -1) return x;
	else return fn(par[x]);
}
vector<int> dsu[800005];
inline void un(int x, int y){
	x = fn(x);
	y = fn(y);
	if(x == y) return;
	if(sz[x] < sz[y]){
		swap(x, y);
	}
	sz[x] += sz[y];
	par[y] = x;
	dsu[x].push_back(y);
}
const int MAGIC = 200003;
vector<int> tour;
int st[1000005];
void dfs(int u, int p = -1){
	if(u == MAGIC-1){
		vector<int> tg;
		for(int v : dsu[u]){
			if(v == p) continue;
			tg.push_back(v);
		}
		dfs(tg[0], u);
		tour.push_back(u);
		st[u] = tour.size()-1;
		for(int i = 1; i < tg.size(); i++){
			dfs(tg[i], u);
			tour.push_back(u);
		}
	}else{
		tour.push_back(u);
		st[u] = tour.size()-1;
		for(int v : dsu[u]){
			if(v == p) continue;
			if(v >= MAGIC){
				tour.push_back(v);
				st[v] = tour.size()-1;
			}else{
				dfs(v, u);
			}
		}
	}
}
int lb[2*1048576];
int rb[2*1048576];
int seg[2*1048576];
int sidx[2*1048576];
void build(int c, int l, int r){
	lb[c] = l;
	rb[c] = r;
	if(l == r){
		seg[c] = p[tour[l]];
		sidx[c] = l;
		return;
	}
	int k = (l+r)/2;
	build(2*c, l, k);
	build(2*c+1, k+1, r);
	if(seg[2*c] < seg[2*c+1]){
		seg[c] = seg[2*c+1];
		sidx[c] = sidx[2*c+1];
	}else{
		seg[c] = seg[2*c];
		sidx[c] = sidx[2*c];
	}
}
void update(int c, int i, int x){
	if(lb[c] == rb[c]){
		seg[c] = x;
		return;
	}
	int k = (lb[c] + rb[c])/2;
	if(i <= k){
		update(2*c, i, x);
	}else{
		update(2*c+1, i, x);
	}
	if(seg[2*c] < seg[2*c+1]){
		seg[c] = seg[2*c+1];
		sidx[c] = sidx[2*c+1];
	}else{
		seg[c] = seg[2*c];
		sidx[c] = sidx[2*c];
	}
}
pair<int,int> query(int c, int l, int r){
	if(lb[c] == l && rb[c] == r) return make_pair(seg[c], sidx[c]);
	int k = (lb[c] + rb[c])/2;
	if(l <= k && k < r){
		auto p1 = query(2*c, l, k);
		auto p2 = query(2*c+1, k+1, r);
		if(p1.first < p2.first) return p2;
		else return p1;
	}else if(r <= k) return query(2*c, l, r);
	else return query(2*c+1, l, r);
}
int main(){
	memset(par, -1, sizeof(par));
	fill(sz, sz+500005, 1);
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m,q;
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i++){
		cin >> p[i];
	}
	vector<pair<int,int> > edges;
	for(int i = 0; i < m; i++){
		int u, v;
		cin >> u >> v;
		edges.emplace_back(u, v);
	}
	vector<int> queries;
	set<int> isdel;
	stack<int> stk;
	for(int i = 0; i < q; i++){
		int c, x;
		cin >> c >> x;
		if(c == 1) x = -x;
		queries.push_back(x);
		if(c == 2){
			isdel.insert(x-1);
			stk.push(x-1);
		}
	}
	for(int i = 0; i < m; i++){
		if(isdel.find(i) == isdel.end()){
			un(edges[i].first, edges[i].second);
		}
	}
	while(!stk.empty()){
		int midx = stk.top();
		stk.pop();
		int f1 = fn(edges[midx].first);
		int f2 = fn(edges[midx].second);
		if(f1 == f2){
			dsu[f1].push_back(MAGIC+midx);
			par[MAGIC+midx] = f1;
			continue;
		}
		if(sz[f1] < sz[f2]){
			swap(f1, f2);
		}
		dsu[f1].push_back(MAGIC+midx);
		dsu[f1].push_back(f2);
		par[MAGIC+midx] = f1;
		par[f2] = f1;
		sz[f1] += sz[f2];
	}
	set<int> roots;
	for(int i = 1; i <= n; i++) roots.insert(fn(i));
	for(int u : roots){
		dsu[MAGIC-1].push_back(u);
		par[u] = MAGIC-1;
		sz[MAGIC-1] += sz[u];
	}
	dfs(MAGIC-1);
	build(1, 0, tour.size()-1);
	isdel.clear();
	for(int i = 0; i < tour.size(); i++){
		if(tour[i] == MAGIC-1) isdel.insert(i);
	}
	for(int i = 0; i < q; i++){
		if(queries[i] < 0){
			int x = -queries[i];
			int idx = st[x];
			int l = 0;
			auto it = isdel.lower_bound(idx);
			if(it != isdel.begin()){
				it--;
				l = *it+1;
			}
			it = isdel.upper_bound(idx);
			int r = tour.size()-1;
			if(it != isdel.end()){
				r = *it-1;
			}
			auto pr = query(1, l, r);
			update(1, pr.second, 0);
			cout << pr.first << '\n';
		}else{
			isdel.insert(st[MAGIC+queries[i]-1]);
		}
	}
	return 0;
}

#include<bits/stdc++.h>

using namespace std;
const int N=5e5+5;
const int B=20;

vector<int>vc[N];
int dfn[N],seq[N],anc[N][B+1],out[N];
int idc;
void dfs(int u){
	dfn[u]=++idc;
	seq[idc]=u;
	for(int i=1;i<=B;i++)
		anc[u][i]=anc[anc[u][i-1]][i-1];
	for(auto v:vc[u]){
		anc[v][0]=u;
		dfs(v);
	}
	out[u]=idc;
}

#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r

struct nod{
	int val,pos;
}tree[N<<2];
int a[N];
nod max(nod a,nod b){
	if(a.val>b.val)return a;
	if(a.val<b.val)return b;
	return seq[a.pos]<seq[b.pos]?a:b;
}

void upda(const int &o){
	tree[o]=max(tree[o<<1],tree[o<<1|1]);
}
void build(int o,int l,int r){
	if(l==r){tree[o].val=a[seq[l]];tree[o].pos=l;return ;}
	int mid=(l+r)>>1;
	build(lson);build(rson);
	upda(o);
}
void modify(int o,int l,int r,int pos){
	if(l==r){tree[o].val=0;return ;}
	int mid=(l+r)>>1;
	if(pos<=mid)modify( lson , pos );
	if(pos >mid)modify( rson , pos );
	upda(o);
}
nod query(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R)return tree[o];
	int mid=(l+r)>>1;
	nod ans;ans.val=0;ans.pos=l;
	if(L<=mid)ans=max(ans,query(lson,L,R));
	if(R >mid)ans=max(ans,query(rson,L,R));
	return ans;
}

int n,m,q,xx,yy,fx,fy,tot;
int ssiz[N],f[N],tim[N];
struct bian{
	int fr,to;
}e[N];
struct RW{
	int opt,id;
}rw[N];
bool ban[N];
int find(int x){
	if(x==f[x])return x;
	return f[x]=find(f[x]);
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&xx,&yy);
		e[i].fr=xx;
		e[i].to=yy;
	}
	for(int i=1;i<=q;i++){
		scanf("%d%d",&xx,&yy);
		rw[i].opt=xx;
		rw[i].id=yy;
		if(rw[i].opt==2)ban[rw[i].id]=1;
	}
	for(int i=1;i<=n*2;i++){
		f[i]=i;ssiz[i]=(i<=n);
	}
	for(int i=1;i<=m;i++){
		if(ban[i])continue;
		fx=find(e[i].fr);
		fy=find(e[i].to);
		if(fx==fy)continue;
		f[fx]=fy;ssiz[fy]+=ssiz[fx];
	}
	tot=n;
	for(int i=1;i<=n;i++){
		if(ssiz[find(i)]==1) continue;
		if(find(i)==i){f[i]=++tot;tim[tot]=q+1;}
	}
	for(int i=1;i<=n;i++){
		if(find(i)==i)continue;
		vc[find(i)].push_back(i);
	}
	for(int i=q;i>=1;i--){
		if(rw[i].opt==1)continue;
		fx=find(e[rw[i].id].fr);
		fy=find(e[rw[i].id].to);
		if(fx==fy)continue;
		++tot;
		f[fx]=f[fy]=tot;
		vc[tot].push_back(fx);
		vc[tot].push_back(fy);
		tim[tot]=i;
	}
	//cout<<"n*2 "<<n*2<<endl;
	//cout<<"tot "<<tot<<endl;
	for(int i=1;i<=tot;i++){
		if(find(i)==i){
			dfs(i);
		}
	}
	//idc=n*2;
	build(1,1,idc);
	for(int i=1;i<=q;i++){
		if(rw[i].opt==2)continue;
		int u=rw[i].id;
		for(int j=B;j>=0;j--){
			if(tim[anc[u][j]]>=i)u=anc[u][j];
		}
		nod tmp=query(1,1,idc,dfn[u],out[u]);
		if(tmp.val)modify(1,1,idc,tmp.pos);
		printf("%d\n",tmp.val);
	}
	return 0;
}
/*
#include<bits/stdc++.h>

using namespace std;
const int N=4e2+5;
const int B=25;

vector<int>vc[N];
int dfn[N],seq[N],anc[N][B+2],out[N];
int idc;
void dfs(int u){
	dfn[u]=++idc;
	seq[idc]=u;
	for(int i=1;i<=B;i++)
		anc[u][i]=anc[anc[u][i-1]][i-1];
	for(auto v:vc[u]){
		anc[v][0]=u;
		dfs(v);
	}
	out[u]=idc;
}

#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r

struct nod{
	int val,pos;
}tree[N<<2];
int a[N];
nod max(nod a,nod b){
	if(a.val>b.val)return a;
	if(a.val<b.val)return b;
	return seq[a.pos]<seq[b.pos]?a:b;
}

void upda(const int &o){
	tree[o]=max(tree[o<<1],tree[o<<1|1]);
}
void build(int o,int l,int r){
	if(l==r){tree[o].val=a[seq[l]];tree[o].pos=l;return ;}
	int mid=(l+r)>>1;
	build(lson);build(rson);
	upda(o);
}
void modify(int o,int l,int r,int pos){
	if(l==r){tree[o].val=0;return ;}
	int mid=(l+r)>>1;
	if(pos<=mid)modify(lson,pos);
	if(pos >mid)modify(rson,pos);
	upda(o);
}
nod query(int o,int l,int r,int L,int R){
	if(L<=l&&r<=R)return tree[o];
	int mid=(l+r)>>1;
	nod ans;ans.val=0;ans.pos=l;
	if(L<=mid)ans=max(ans,query(lson,L,R));
	if(R >mid)ans=max(ans,query(rson,L,R));
	return ans;
}

int n,m,q,xx,yy,fx,fy,tot;
int ssiz[N],f[N],tim[N];
struct bian{
	int fr,to;
}e[N];
struct RW{
	int opt,id;
}rw[N];
bool ban[N];
int find(int x){
	if(x==f[x])return x;
	return f[x]=find(f[x]);
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&xx,&yy);
		e[i].fr=xx;
		e[i].to=yy;
	}
	for(int i=1;i<=q;i++){
		scanf("%d%d",&xx,&yy);
		rw[i].opt=xx;
		rw[i].id=yy;
		if(rw[i].opt==2)ban[rw[i].id]=1;
	}
	for(int i=1;i<=n*2;i++){
		f[i]=i;ssiz[i]=(i<=n);
	}
	for(int i=1;i<=m;i++){
		if(ban[i])continue;
		fx=find(e[i].fr);
		fy=find(e[i].to);
		if(fx==fy)continue;
		f[fx]=fy;ssiz[fy]+=ssiz[fx];
	}
	tot=n;
	for(int i=1;i<=n;i++){
		if(ssiz[find(i)]==1) continue;
		if(find(i)==i){f[i]=++tot;tim[tot]=q+1;}
	}
	for(int i=1;i<=n;i++){
		if(find(i)==i)continue;
		vc[find(i)].push_back(i);
	}
	for(int i=q;i>=1;i--){
		if(rw[i].opt==1)continue;
		fx=find(e[rw[i].id].fr);
		fy=find(e[rw[i].id].to);
		if(fx==fy)continue;
		++tot;
		f[fx]=f[fy]=tot;
		vc[tot].push_back(fx);
		vc[tot].push_back(fy);
		tim[tot]=i;
	}
	for(int i=1;i<=tot;i++){
		if(find(i)==i){
			dfs(i);
		}
	}
	build(1,1,idc);
	for(int i=1;i<=q;i++){
		if(rw[i].opt==2)continue;
		int u=rw[i].id;
		for(int j=0;j<=B;j++){
			if(tim[anc[u][j]]>=i)u=anc[u][j];
		}
		//printf("%d\n",u);
		nod tmp=query(1,1,idc,dfn[u],out[u]);
		modify(1,1,idc,tmp.pos);
		printf("%d\n",tmp.val);
	}
	return 0;
}
*/

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define mkp make_pair
#define rint register int
#define INF ((1 << 30) - 1)
#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Pair pair < int, int >
#define mst(a,b) memset(a,b,sizeof(a))
#define foR(i, k, j) for(rint i = (k); i >= (j); i--)
#define For(i, k, j) for(rint i = (k); i <= (j); i++)
#define Foe(i, u) for(rint i = lst[u], v = e[i].v; i; i = e[i].nxt, v = e[i].v)
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define file(s) freopen(s".in", "r", stdin); freopen(s".out", "w", stdout)
//#define int long long
const int P = 1000000007; //
using namespace std;
inline void ckmax(int &a, int b) {a = max(a, b);}
inline void ckmin(int &a, int b) {a = min(a, b);}
inline void mulmod(int &a, int b) {a = 1ll * a * b % P;}
inline void addmod(int &a, int b) {int t = a + b; a = (t >= P ? t - P : t); }
inline int ksm(int a, int b) {int ans=1; for(;b;b>>=1) {if(b&1) ans=1ll*ans*a%P;a=1ll*a*a%P;}return ans;}
inline int inv(int a) {return ksm(a, P-2);}

inline void printarray(int *a, int n) {For(i, 1, n) fprintf(stderr, "%d ", a[i]); fprintf(stderr, "\n");}
namespace FastIO {
    const int SIZE=1<<16; char buf[SIZE], obuf[SIZE], str[64]; int bi=SIZE, bn=SIZE, opt;
    int read(char *s) {
        while (bn) {for (;bi<bn&&buf[bi]<=' ';bi++);if (bi<bn) break; bn=fread(buf,1,SIZE,stdin),bi=0;}
        int sn=0;while (bn) {for (;bi<bn&&buf[bi]>' ';bi++) s[sn++]=buf[bi];if (bi<bn) break; bn=fread(buf,1,SIZE,stdin),bi=0;}s[sn]=0;return sn;
    }
    bool read(int& x) {if(x)x=0;int bf=0,n=read(str); if(!n) return 0; int i=0; if (str[i]=='-') bf=1,i=1; for(x=0;i<n;i++) x=x*10+str[i]-'0'; if(bf) x=-x; return 1;}
    void write(int x) {
        if(!x) obuf[opt++] = '0'; else {if(x<0) obuf[opt++]='-',x=-x;int sn=0; while(x)str[sn++]=x%10+'0',x/=10;for (int i=sn-1;i>=0;i--) obuf[opt++]=str[i];}
        if (opt>=(SIZE>>1)){fwrite(obuf, 1, opt, stdout); opt=0;}
    }
    void write(char x) {obuf[opt++]=x;if (opt>=(SIZE>>1)){fwrite(obuf, 1, opt, stdout); opt=0;}}
    void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt=0;}
};
const int MAXN = 1e6 + 5;
int n, m, q, a[MAXN], o[MAXN], p[MAXN], u[MAXN], v[MAXN], used[MAXN];
vector < int > e[MAXN];

int f[MAXN], cnt = 0;
inline int find(int x) {
	while(x != f[x]) x = f[x] = f[f[x]];
	return x;
}
inline void merge(int x, int y) {
	x = find(x), y = find(y);
	if(x == y) return;
	cnt++; e[cnt].pb(f[x]), e[cnt].pb(f[y]);
	f[x] = f[y] = cnt;
}

int dfn[MAXN], id[MAXN], siz[MAXN], ind;
inline void dfs(int u) {
	id[dfn[u] = ++ind] = u, siz[u] = 1;
	for(auto v : e[u]) {
		dfs(v), siz[u] += siz[v];
	}
}
struct Segment_tree {
	pair < int, int > mx[MAXN << 2];
	#define ls (k << 1)
	#define rs (k << 1 | 1)
	#define mid ((l + r) >> 1)
	pair < int, int > merge(pair < int, int > a, pair < int, int > b) {
		if(a.first > b.first) return a;
		else return b;
	}
	void update(int k, int l, int r, int pos, int val) {
		if(l == r) return mx[k] = mkp(val, l), void();
		pos <= mid ? update(ls, l, mid, pos, val) : update(rs, mid+1, r, pos, val);
		mx[k] = merge(mx[ls], mx[rs]);
	}

	Pair query(int k, int l, int r, int ql, int qr) {
		if(l == ql && r == qr) return mx[k];
		if(qr <= mid) return query(ls, l, mid, ql, qr);
		if(mid < ql) return query(rs, mid+1, r, ql, qr);
		return merge(query(ls, l, mid, ql, mid), query(rs, mid+1, r, mid+1, qr));
	}
}tr;
signed main()
{
    #ifndef ONLINE_JUDGE
        file("pro");
    #endif
    cin >> n >> m >> q;
    For(i, 1, n) FI(a[i]);
    For(i, 1, m) FI(u[i]), FI(v[i]);
    For(i, 1, q) {
    	FI(o[i]), FI(p[i]);
    	if(o[i] == 2) used[p[i]] = 1;
	}
	For(i, 1, 2 * n) f[i] = i; cnt = n;
	For(i, 1, m)
		if(!used[i]) merge(u[i], v[i]);
    foR(i, q, 1) {
    	if(o[i] == 1) p[i] = find(p[i]);
		else merge(u[p[i]], v[p[i]]);
	}
//	cerr << "?";
	cnt++;
	For(i, 1, cnt - 1)
		if(find(i) == i) e[cnt].pb(i);
	dfs(cnt);
//	For(i, 1, n) cerr << dfn[i] << endl;
	For(i, 1, n) tr.update(1, 1, cnt, dfn[i], a[i]);
	For(i, 1, q) {
		if(o[i] == 1) {
//			cerr << p[i] << endl;
//			cerr << dfn[p[i]] << ' ' << dfn[p[i]] + siz[p[i]] - 1 << endl;
			Pair res = tr.query(1, 1, cnt, dfn[p[i]], dfn[p[i]] + siz[p[i]] - 1);
			printf("%d\n", res.first);
//			cerr << res.second << endl;
			tr.update(1, 1, cnt, res.second, 0);
		}
	}
    return 0;
}
/*

4 7 1
2 1 8
2 4 2
4 3 2
3 2 8
2 3 5
4 3 1
2 4 5
2 9
*/

#include <bits/stdc++.h>
//#define ACM_LOCAL
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 4e5 + 10;
const int M = 1e6 + 10;
const int MOD = 1e9 + 7;

struct Hash {
    int b[N], tot;
    void init() { tot = 0; }
    void insert(int x) { b[++tot] = x; }
    void build() {
        sort(b + 1, b + 1 + tot);
        tot = unique(b + 1, b + 1 + tot) - (b + 1);
    }
    int pos(int x) { return lower_bound(b + 1, b + 1 + tot, x) - b; }
} ha;
struct Edge {
    int u, v, w;
    bool operator < (const Edge &rhs) const {
        return w < rhs.w;
        // > 最大边中的最小值
        // < 最小边中的最大值
    }
} e[M];

int n, m, d[N], dfn[N], t, f[N][20], q, idx, rnk[N], in[N], out[N];
int cnt, val[N], fa[N], a[N];
int rt[N], NodeNum;
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }

vector<int> g[N];

void dfs(int x, int fa) {
    rnk[dfn[x] = ++idx] = x, f[x][0] = fa, d[x] = d[fa] + 1;
    for (int i = 1; i <= 19; i++) f[x][i] = f[f[x][i-1]][i-1];
    in[x] = idx;
    for (auto &y : g[x])
        if (y != fa) dfs(y, x);
    out[x] = idx;
}

void exKruskal() {
    cnt = n; for (int i = 1; i < (n << 1); i++) fa[i] = i;
    sort(e + 1, e + 1 + m);
    for (int i = 1; i <= m; i++) {
        int u = find(e[i].u), v = find(e[i].v);
        if (u == v) continue;
        val[++cnt] = e[i].w;
        fa[u] = fa[v] = cnt;
        g[u].push_back(cnt), g[cnt].push_back(u);
        g[v].push_back(cnt), g[cnt].push_back(v);
        if (cnt == (n << 1) - 1) break;//最多2N-1个点
    }
    for (int i = 1; i <= cnt; i++)
        if (!d[i]) {//未访问过
            int rt = find(i);//下树剖lca
            dfs(rt, 0);
        }
}
int FindPoint (int x, int p) {
    for (int i = 20; i >= 0; i--)
        if (d[x] > (1 << i) && val[f[x][i]] <= p) x = f[x][i];
    return x;
}

struct Node {
    int L[N<<2], R[N<<2], maxx[N<<2], id[N<<2];

    void push_up(int u) {
        if (maxx[u<<1] >= maxx[u<<1|1]) {
            maxx[u] = maxx[u<<1];
            id[u] = id[u<<1];
        }
        else {
            maxx[u] = maxx[u<<1|1];
            id[u] = id[u<<1|1];
        }
    }
    void build(int u, int l, int r) {
        L[u] = l, R[u] = r;
        if (l == r) {
            maxx[u] = a[rnk[l]];
            id[u] = l;
            return;
        }
        int mid = l + r >> 1;
        build(u<<1, l, mid);
        build(u<<1|1, mid+1, r);
        push_up(u);
    }
    void modify(int u, int pos, int val) {
        if (L[u] == R[u]) {
            maxx[u] = val;
            return;
        }
        int mid = L[u] + R[u] >> 1;
        if (pos <= mid) modify(u<<1, pos, val);
        else modify(u<<1|1, pos, val);
        push_up(u);
    }
    PII query(int u, int ql, int qr) {
        if (ql <= L[u] && qr >= R[u]) {
            return {maxx[u], id[u]};
        }
        int mid = L[u] + R[u] >> 1;
        PII Max = {0, 0};
        if (ql <= mid) Max = max(query(u<<1, ql, qr), Max);
        if (qr > mid) Max = max(query(u<<1|1, ql, qr), Max);
        return Max;
    }
}tr;
struct Q {
    int opt, x;
}qry[M];

void ask(int x, int p) {
    int Point = FindPoint(x, p);
    PII Max = tr.query(1, in[Point], out[Point]);
    printf("%d\n", Max.first);
    tr.modify(1, Max.second, 0);
}

void solve() {
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        e[i] = {u, v, 1};
    }
    for (int i = 1; i <= q; i++) {
        cin >> qry[i].opt >> qry[i].x;
        if (qry[i].opt == 2) e[qry[i].x].w = INF - i;
    }
    exKruskal();
    tr.build(1, 1, idx);
    for (int i = 1; i <= q; i++) {
        int p = INF - i;
        if (qry[i].opt == 1) {
            ask(qry[i].x, p);
        }
    }

}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
    return 0;
}

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <iomanip>
#include <set>
#include <tuple>
#define mkp make_pair
#define mkt make_tuple
#define rep(i,n) for(int i = 0; i < (n); ++i)
#define all(v) v.begin(),v.end()
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
template<class T> void chmin(T &a,const T &b){if(a>b) a=b;}
template<class T> void chmax(T &a,const T &b){if(a<b) a=b;}

class DisjointSet{
public:
  int N;
  vector<int> rank,p;
  vector<int> sz;

  vector<set<int>> vse;
  vector<int> P;
  vector<pair<int,int>> undo_pair;

  DisjointSet(){}
  DisjointSet(int n,vector<int> P,int TL):N(n),rank(n),p(n),sz(n),P(P),vse(n){
    for(int i=0;i<N;i++) makeSet(i);
    undo_pair.resize(TL,mkp(-1,-1));
  }

  void makeSet(int x){
    p[x]=x;
    rank[x]=0;
    sz[x]=1;
    vse[x].insert(P[x]);
  }

  bool same(int x,int y){
    return leader(x)==leader(y);
  }

  void unite(int x,int y,int t){
    if(same(x,y)) return;
    link(leader(x),leader(y),t);
  }

  void link(int x,int y,int t){
    if(sz[x]>sz[y]) swap(x,y);

    undo_pair[t]=mkp(x,y);
    p[x]=y;
    sz[y]+=sz[x];
    for(auto s:vse[x]) vse[y].insert(s);
    /*if(rank[x]==rank[y]){
      ++rank[y];
    }*/
  }

  int leader(int x){
    if(x!=p[x]){
      return leader(p[x]);
    }
    return p[x];
  }

  int size(int x){
    return sz[leader(x)];
  }

  void undo(int t){
    if(undo_pair[t]==mkp(-1,-1)) return;
    int x,y;
    tie(x,y)=undo_pair[t];
    for(auto s:vse[x]) vse[y].erase(s);
    p[x]=x;
  }
};

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N,M,Q;
  cin>>N>>M>>Q;
  vector<int> P(N);
  rep(i,N) cin>>P[i];
  vector<int> A(M),B(M);
  rep(i,M) cin>>A[i]>>B[i];

  rep(i,N) P[i]--;
  rep(i,M){
    A[i]--;B[i]--;
  }
  vector<pair<int,int>> qry(Q);
  rep(i,Q){
    int t,v;
    cin>>t>>v;
    v--;
    qry[i]=mkp(t,v);
  }

  vector<int> exi(M,0);
  rep(i,Q) if(qry[i].first==2) exi[qry[i].second]=1;

  DisjointSet us(N,P,Q+10);
  rep(i,M) if(exi[i]==0) us.unite(A[i],B[i],Q);
  for(int i=Q-1;i>=0;i--){
    if(qry[i].first==2){
      int t=qry[i].second;
      us.unite(A[t],B[t],i);
    }
  }

  vector<int> used(N+1,0);
  vector<int> ans;
  for(int i=0;i<Q;i++){
    int t,v;
    tie(t,v)=qry[i];
    if(t==1){
      int res=-1;
      int p=us.leader(v);
      while(us.vse[p].size()){
        auto itr=us.vse[p].end();
        --itr;
        int val=*itr;
        us.vse[p].erase(itr);
        if(used[val]==0){
          used[val]=1;
          res=val;
          break;
        }
      }
      ans.push_back(res);
    }else{
      us.undo(i);
    }
  }

  for(auto n:ans) cout<<n+1<<"\n";

  return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int QQ = 500000;
int P[200000];

// par[x] = y; x, prv
vector<pair<int, int>> undo_par[QQ+1];
// st[y].insert(v); y, v
vector<pair<int, int>> undo_st[QQ+1];

struct UnionFind {
    vector<int> par;
    vector<int> sz;
    vector<set<int>> st;

    UnionFind(int n=0){ if(n>0) initialize(n); }
    void initialize(int n){
        par.resize(n);
        sz.assign(n, 1);
        st.resize(n);
        for(int i=0; i<n; i++){
            par[i] = i;
            st[i].insert(P[i]);
        }
    }

    int find(int x){
        if(par[x] == x){
            return x;
        }else{
            return find(par[x]);
        }
    }

    bool unite(int x, int y, int t){
        x = find(x), y = find(y);
        if(x == y) return false;
        if(sz[x] > sz[y]) swap(x, y);
        undo_par[t].emplace_back(x, par[x]);
        par[x] = y;
        sz[y] += sz[x];
        for(int v : st[x]){
            st[y].insert(v);
            undo_st[t].emplace_back(y, v);
        }
        return true;
    }

    void undo(int t){
        for(auto [y, v] : undo_st[t]) st[y].erase(v);
        for(auto [x, prv] : undo_par[t]) par[x] = prv;
    }

    bool same(int x, int y){ return find(x) == find(y); }
    int size(int x){ return sz[find(x)]; }
};

int main(){
    int N, M, Q;
    cin >> N >> M >> Q;
    for(int i=0; i<N; i++) scanf("%d", &P[i]);
    vector<pair<int, int>> es(M);
    for(int i=0; i<M; i++){
        int a, b;
        scanf("%d %d", &a, &b);
        a--; b--;
        es[i] = {a, b};
    }
    vector<bool> e_live(M, true);
    vector<int> tp(Q), tv(Q);
    for(int q=0; q<Q; q++){
        scanf("%d %d", &tp[q], &tv[q]);
        tv[q]--;
        if(tp[q] == 2) e_live[tv[q]] = false;
    }

    UnionFind uf(N);
    for(int i=0; i<M; i++) if(e_live[i]) uf.unite(es[i].first, es[i].second, Q);
    for(int q=Q-1; q>=0; q--){
        if(tp[q] == 2){
            auto [a, b] = es[tv[q]];
            uf.unite(a, b, q);
        }
    }

    vector<bool> used(N+1);

    for(int q=0; q<Q; q++){
        if(tp[q] == 1){
            int c = uf.find(tv[q]), ans = 0;
            auto& st = uf.st[c];
            while(st.size() && used[*prev(st.end())]) st.erase(prev(st.end()));
            if(st.size()){
                auto it = prev(uf.st[c].end());
                ans = *it;
                used[ans] = true;
                uf.st[c].erase(it);
            }
            printf("%d\n", ans);
        }else{
            uf.undo(q);
        }
    }
    return 0;
}

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<climits>
#include<bitset>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=4e5+11;
int N,M,T[MAXN];vector<int> vec[MAXN];
struct Segment{
    int Maxn[MAXN<<2];
    void Modify(int k,int l,int r,int ps,int w){
        if(l==r){Maxn[k]=w;return;}
        int mid=(l+r)>>1;if(ps<=mid) Modify(k<<1,l,mid,ps,w);else Modify(k<<1|1,mid+1,r,ps,w);
        Maxn[k]=max(Maxn[k<<1],Maxn[k<<1|1]);return;
    }
    int Query(int k,int l,int r,int x,int y){
        //cerr<<"l:"<<l<<" r:"<<r<<" "<<x<<" "<<y<<endl;
        if(x<=l&&r<=y) return Maxn[k];int mid=(l+r)>>1,res=0;
        if(x<=mid) res=max(res,Query(k<<1,l,mid,x,y));
        if(mid<y) res=max(res,Query(k<<1|1,mid+1,r,x,y));
        return res;
    }
}S;
struct Edge{int u,v,tim;}E[MAXN];
bool cmp(Edge x1,Edge x2){return x1.tim>x2.tim;}
struct Union{
    int f[MAXN];void init(){for(int i=1;i<=2*N;i++) f[i]=i;return;}
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
}U;pii Que[MAXN];
int dfn[MAXN],siz[MAXN],INF=INT_MAX,MM[MAXN],Val[MAXN],dep[MAXN],tot,fa[MAXN][21],cnt,Q;
void dfs(int u,int fath){
    dep[u]=dep[fath]+1;fa[u][0]=fath;if(u<=N) siz[u]=1,dfn[u]=++dfn[0];
    for(int i=1;(1<<i)<=dep[u];i++) fa[u][i]=fa[fa[u][i-1]][i-1];
    for(auto v:vec[u]) if(v!=fath) dfs(v,u),siz[u]+=siz[v],dfn[u]=min(dfn[u],dfn[v]);return;
}
int Qmax(int u,int t){
    for(int i=20;i>=0;i--) if(T[fa[u][i]]>=t&&fa[u][i]) u=fa[u][i];
    return u;
}
int main(){
    //freopen("D.in","r",stdin);
    N=read(),M=read(),Q=read();U.init();tot=N;
    for(int i=1;i<=N;i++) Val[i]=read(),MM[Val[i]]=i;
    for(int i=1;i<=M;i++) E[i].u=read(),E[i].v=read(),E[i].tim=INF;int ps=0;
    for(int i=1;i<=Q;i++){int opt=read(),u=read();if(opt==1) Que[++cnt].fi=u,Que[cnt].se=ps;else E[u].tim=ps=i;}sort(E+1,E+M+1,cmp);
    for(int i=1;i<=M;i++){
        int u=E[i].u,v=E[i].v,tim=E[i].tim;
        if(U.find(u)==U.find(v)) continue;
        u=U.find(u),v=U.find(v);
        //cerr<<"u:"<<u<<" v:"<<v<<" tim:"<<tim<<endl;
        ++tot;U.f[u]=U.f[v]=tot;T[tot]=tim;
        vec[tot].pb(u),vec[tot].pb(v);
    }memset(dfn,127/3,sizeof(dfn));dfn[0]=0;
    for(int i=1;i<=tot;i++) if(U.find(i)==i) dfs(i,0);
    for(int i=1;i<=N;i++) S.Modify(1,1,N,dfn[i],Val[i]);
    //return 0;
    //for(int i=1;i<=2*N-1;i++) printf("%d ",dfn[i]);printf("\n");
    for(int i=1;i<=cnt;i++){
        int u=Que[i].fi,tim=Que[i].se+1;
        int G=Qmax(u,tim),L=dfn[G],R=dfn[G]+siz[G]-1,WW;
        //return 0;
        printf("%d\n",WW=S.Query(1,1,N,L,R));
        //return 0;
        if(!WW) continue;
        S.Modify(1,1,N,dfn[MM[WW]],0);
    }return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)/2)
using namespace std;
int n, m, q;

int A[1000009],B[1000009];
vector<int> adj[1000009];
int arr[1000009],l[1000009],r[1000009],per[1000009],p[1000009], No[1000009],cor[1000009];
int P(int x){
    if(p[x] == x) return x;
    p[x] = P(p[x]);
    return p[x];

}
int c = 0;
void dfs(int x){
    if(x <= n) {arr[++c] = per[x], l[x] = c, r[x] = c;
    return;
    }
    l[x] = n, r[x] = 1;
    for(int y : adj[x]){
        dfs(y);
        l[x] = min(l[x], l[y]);
        r[x] = max(r[x], r[y]);

    }

}
set<pair<int,int> > S;
void rem(int x){
    S.erase(S.find({l[x], r[x]}));
    for(int y : adj[x]){
        S.insert({l[y], r[y]});
    }
}
struct node{
    int mx;
    node *L, *R;
    void upd(){
        this->mx = max(this->L->mx, this->R->mx);
    }
};
void build(node *&x, int l, int r){
    x = new node();
    if(l==r) {x->mx = arr[l]; return;}
    build(x->L,l,mid);
    build(x->R,mid+1,r);
    x->upd();
}
void upd(node *&x, int l, int r, int p){
    if(p < l || p > r) return;
    if(l == r){
        x ->mx = 0;
        return;
    }
    upd(x->L,l,mid,p);
    upd(x->R,mid+1,r,p);
    x->upd();
}
int cnt(node *&x, int l, int r, int a, int b){
    if(l > b || r  < a) return 0;
    if(l >= a && r <= b) return x->mx;
    return max(cnt(x->L,l,mid,a,b),
               cnt(x->R,mid+1,r,a,b));

}
main(){
    scanf("%d %d %d", &n, &m, &q);
    for(int i = 1; i <= n; i++){
        scanf("%d", &per[i]);
        cor[per[i]] = i;
    }
    for(int i = 1; i <= m; i++){
         scanf("%d %d", &A[i], &B[i]);
    }
    int Z = m;
    vector<pair<int,int> > Q;
    for(int i = 1; i <= q; i++){
        int t;
        scanf("%d", &t);
        if(t == 1){
            int v;

            scanf("%d", &v);
            Q.push_back({v, Z});
        }
        else {
            int i;

            scanf("%d", &i);
            No[i] = Z;
            Z--;
        }
    }
    vector<pair<int,int> > O;
    for(int i = 1; i <= m; i++){
        O.push_back({No[i],i});
    }
    sort(O.begin(), O.end());
    for(int i = 1; i <= n+m+1; i++){
        p[i] = i;

    }
    for(int i = 0; i < m; i++){
        int x = O[i].second;
        int u = P(A[x]), v = P(B[x]);
        if(u == v) continue;
        p[u] = n + i + 1, p[v] = n + i + 1;
        adj[n+i+1].push_back(u);
        adj[n+i+1].push_back(v);
    }
     adj[n+m+1].push_back(P(1));
    for(int i = 1; i < n; i++){

        int u = P(i), v = P(i+1);
        if(u == v) continue;
        p[u] = n+m+1, p[v] = n+m+1;
        adj[n+m+1].push_back(v);
    }
    dfs(n+m+1);
    S.insert({1,n});
    int mx = n + m + 1;
    node *rt;
    build(rt, 1, n);
    for(int i = 0; i < Q.size(); i++){
        int v = Q[i].first, z = Q[i].second;
        while(mx > n + z){
            if(!l[mx]) {mx--; continue;}
            rem(mx);
            mx--;

        }

        auto it = S.lower_bound({l[v]+1, -1});
        it--;
        int L = it->first, R = it->second;
        int u = cnt(rt, 1, n, L, R);
        printf("%d\n", u);
        int ind = l[cor[u]];
        upd(rt,1,n, ind);

    }

}/*

5 5 5
1 2 3 4 5
1 2
2 3
3 4
4 5
5 1
1 1
2 1
2 2
1 5
1 1*/

/*--------------------------------------------------------------------
      JENISH MONPARA S.       IIT PATNA         I LOVE ADITI GOEL
--------------------------------------------------------------------*/
#include <bits/stdc++.h>
using namespace std;
long double PI = 3.14159265359;
long double DEL = 1e-10;
int mod =  1000000007;

#define ftt cin>>t;for(int tt=1;tt<=t;++tt)
#define all(a) a.begin() , a.end()
#define sqr(a) ((a) * (a))
#define double long double
#define dbg cout<<"\nhi\n"
#define int long long
#define nl cout<<"\n"
#define pb push_back
#define sp <<" "<<
#define ss second
#define ff first

const int N = 400050;
int cnt, sum, mid, mx, mn, ans, a[N], b[N];
int n, m, d, i, j, k, l, p, que, r, w, x[N], y[N], del[N];
bool f, f1, f2;
string s;
// you can also use __int128
// priority_queue<int,vector<int>,greater<int>>
// bitset<100>(x).count()
//******************************************* CHECK CONSTRAINTS **************************************************
pair<int,int> t[N*4],q[2*N];
int check[2*N],timer = 1,tin[N],tout[N];
vector<int> g[N];

int find(int i)
{
      if(i == a[i])
      {
            return i;
      }
      return a[i] = find(a[i]);
}

void join(int x,int y)
{
      int parx = find(x),pary = find(y);
      if(parx == pary)
      {
            return;
      }
      n++;
      a[parx] = n;
      a[pary] = n;
      a[n] = n;
      g[n].push_back(parx);
      g[n].push_back(pary);
}

void dfs(int i)
{
      tin[i] = timer++;
      for(auto j:g[i])
      {
            dfs(j);
      }
      tout[i] = timer;
}

void update(int i,int l,int r,int x,pair<int,int> v)
{
      if(x < l || x > r || l > r)
      {
            return;
      }
      if(l == r)
      {
            t[i] = v;
            return;
      }
      int y = 2*i;
      update(y,l,(l+r)/2,x,v);
      update(y|1,(l+r+2)/2,r,x,v);
      t[i] = max(t[y],t[y|1]);
}

pair<int, int> query(int i,int l,int r,int a,int b)
{
      if(a <= l and r <= b)
      {
            return t[i];
      }
      if(a > r || b < l || l > r)
      {
            return {0,0};
      }
      int y = 2*i;
      return max(query(y,l,(l+r)/2,a,b),query(y|1,(l+r+2)/2,r,a,b));
}

int32_t main()
{
      ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
      cin>>n>>m>>que;
      for(int i=1;i<=n;i++)
      {
            cin>>b[i];
            a[i] = i;
      }
      for(int i=1;i<=m;i++)
      {
            cin>>x[i]>>y[i];
      }
      for(int i=1;i<=que;i++)
      {
            cin>>q[i].ff>>q[i].ss;
            if(q[i].ff == 2)
            {
                  del[q[i].ss] = 1;
            }
      }
      for(int i=1;i<=m;i++)
      {
            if(!del[i])
            {
                  join(x[i],y[i]);
            }
      }
      for(int i=que;i>0;i--)
      {
            if(q[i].ff == 1)
            {
                  check[i] = find(q[i].ss);
            }
            else
            {
                  join(x[q[i].ss],y[q[i].ss]);
            }
      }
      for(int i=1;i<=n;i++)
      {
            if(a[i] == i)
            {
                  dfs(i);
            }
      }
      for(int i=1;i<=n;i++)
      {
            update(1,1,timer,tin[i],{b[i],tin[i]});
      }
      //cerr<<timer sp n;nl;
      //timer--;
      //assert(timer == n);
      for(int i=1;i<=que;i++)
      {
            if(q[i].ff == 1)
            {
                  k = check[i];
                  auto j = query(1,1,timer,tin[k],tout[k]-1);
                  update(1,1,timer,j.ss,{0,j.ss});
                  cout<<j.ff;nl;
            }
      }
}

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
#define all(a) (a).begin(),(a).end()

template<typename T1, typename T2> inline void chkmin(T1 & x, const T2 & y) {if (y < x) x = y;}
template<typename T1, typename T2> inline void chkmax(T1 & x, const T2 & y) {if (x < y) x = y;}

const int N = 1e6 + 10, M = 1e6, Q = 1e6;
int n, m, q;
int p[N];
pair<int, int> e[M];

int type[Q], query[Q];

void read() {
    cin >> n >> m >> q;
    for (int i = 0; i < n; ++i) {
        cin >> p[i];
    }
    for (int i = 0; i < m; ++i) {
        cin >> e[i].first >> e[i].second;
        e[i].first--;
        e[i].second--;
    }
    for (int i = 0; i < q; ++i) {
        cin >> type[i] >> query[i];
        query[i]--;
    }
}

int par[N + M];

int getPar(int v) {
    if (v == par[v]) return v;
    return par[v] = getPar(par[v]);
}

void uni(int a, int b) {
    assert(a != b);
    assert(a == getPar(a));
    //cout << a << " " << getPar(a) << endl;
    //cout << b << " " << getPar(b) << endl;
    assert(b == getPar(b));
    par[a] = b;
}

void init() {
    iota(par, par + n + m, 0);
}

vector<int> g[N + M];
int topG;

void add(int u, int v) {
    //cout << "add: u = " << u << " v = " << v << endl;
    u = getPar(u);
    v = getPar(v);
    if (u == v) return;
    int root = topG++;
    //cout << "root = " << root << endl;
    g[root].push_back(u);
    g[root].push_back(v);
    uni(u, root);
    uni(v, root);
}

bool used[M];

int tin[N], tout[N], timer = 0;

void dfs(int v) {
    used[v] = true;
    tin[v] = timer++;
    for (auto i : g[v]) {
        if (used[i]) continue;
        dfs(i);
    }
    tout[v] = timer - 1;
}

struct Node{
    int pos, val;
    Node() {
        pos = -1, val = -1;
    }
    Node(int _pos, int _val) {
        pos = _pos, val = _val;
    }
};

Node merge(const Node& a, const Node& b) {
    if (a.val < b.val) {
        return b;
    } else {
        return a;
    }
}

struct SegmentTree{
    int n;
    vector<Node> tree;
    vector<int> pos;
    SegmentTree() {}

    void build(int v, int tl, int tr, const vector<int>& a) {
        if (tl >= tr) return;
        if (tl == tr - 1) {
            //cout << "tl = " << tl << " a[tl] = " << a[tl] << endl;
            tree[v] = Node(tl, a[tl]);
            pos[tl] = v;
            return;
        }
        int tm = (tl + tr) / 2;
        build(v * 2, tl, tm, a);
        build(v * 2 + 1, tm, tr, a);
        tree[v] = merge(tree[v * 2], tree[v * 2 + 1]);
    }

    SegmentTree(const vector<int>& a) {
        n = a.size();
        tree.assign(4 * n, Node());
        pos.assign(n, 0);
        build(1, 0, n, a);
        /*
        for (int i = 0; i < n; ++i) {
            tree[i] = Node(i, a[i]);
        }*/
    }

    Node get(int v, int tl, int tr, int l, int r) {
        if (tl >= r || tr <= l) return Node();
        if (tl >= l && tr <= r)
            return tree[v];
        int tm = (tl + tr) / 2;
        return merge(get(v * 2, tl, tm, l, r), get(v * 2 + 1, tm, tr, l, r));
    }

    Node get(int l, int r) {
        assert(l >= 0 && r < n);
        return get(1, 0, n, l, r + 1);
        /*
        Node ans;
        for (int i = l; i <= r; ++i) {
            ans = merge(ans, tree[i]);
        }
        return ans;*/
    }
    void clear(int v) {
        assert(v != -1);
        assert(v >= 0 && v < n);
        tree[pos[v]] = Node(v, 0);
        v = pos[v] / 2;
        while (v) {
            tree[v] = merge(tree[v * 2], tree[v * 2 + 1]);
            v /= 2;
        }
    }
};

int myRoot[Q];
SegmentTree tree;

void build() {
    init();
    for (int i = 0; i < q; ++i) {
        if (type[i] == 2) {
            used[query[i]] = true;
        }
    }
    /*cout << "used = " << endl;
    for (int i = 0; i < m; ++i) {
        cout << used[i] << " ";
    }
    cout << endl;*/
    topG = n;
    for (int i = 0; i < m; ++i) {
        if (!used[i]) {
            add(e[i].first, e[i].second);
        }
    }
    for (int i = q - 1; i >= 0; --i) {
        if (type[i] == 1) {
            myRoot[i] = getPar(query[i]);
        } else if (type[i] == 2) {
            add(e[query[i]].first, e[query[i]].second);
        }
    }
    //cout << "topG = " << topG << endl;
    //assert(n + m == topG);
    fill(used, used + n + m, false);
    for (int i = topG - 1; i >= 0; --i) {
        if (!used[i]) {
            dfs(i);
        }
    }
    vector<int> a(n + m, -1);
    for (int i = 0; i < n; ++i) {
        a[tin[i]] = p[i];
    }
    tree = SegmentTree(a);
}

int topAns;
int ans[Q];

void solve() {
    topAns = 0;
    for (int i = 0; i < q; ++i) {
        if (type[i] == 1) {
            auto have = tree.get(tin[myRoot[i]], tout[myRoot[i]]);
            //cout << "have = ";
            //cout << have.pos << " " << have.val << endl;
            ans[topAns++] = have.val;
            tree.clear(have.pos);
        }
    }
}

void run() {
    build();
    solve();
}

void write() {
    for (int i = 0; i < topAns; ++i) {
        cout << ans[i] << "\n";
    }
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0), cout.precision(20), cout.setf(ios::fixed);
    read();
    run();
    write();
    return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=4e5+9,M=5e6+9,QQ=5e6+9;
#define ls (x<<1)
#define rs (x<<1|1)
#define mp make_pair
#define PII pair<int,int>
struct Tree
{
	pair<int,int> val;
} tr[N<<2];
struct Query
{
	int v,op;
} Q[QQ];
struct Eage
{
	int x,y;
} e[M];
int n,m,q,a[N],dep[N];
int fa[N],siz[N],dfn[N],ind;
vector<int> G[N];
bool vis[M];

int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}

void dfs(int u)
{
	dfn[u]=++ind;
	siz[u]=1;
	for(auto v:G[u]) dfs(v),siz[u]+=siz[v];
}

void change(int x,int l,int r,int pos,PII v)
{
	if(l==r) {tr[x].val=v;return;}
	int mid=(l+r)>>1;
	if(pos<=mid) change(ls,l,mid,pos,v);
	else change(rs,mid+1,r,pos,v);
	tr[x].val=max(tr[ls].val,tr[rs].val);
}

PII query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tr[x].val;
	int mid=(l+r)>>1;
	PII res=mp(0,0);
	if(L<=mid) res=max(res,query(ls,l,mid,L,R));
	if(R>mid) res=max(res,query(rs,mid+1,r,L,R));
	return res;
}

inline void Merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return;
	// if(dep[fx]>dep[fy]) swap(fx,fy);
	fa[fx]=fa[fy]=++n;
	fa[n]=n;
	G[n].push_back(fx);
	G[n].push_back(fy);
	// if(dep[fx]==dep[fy]) dep[fy]++;
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),fa[i]=i,dep[i]=1;
	for(int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&Q[i].op,&Q[i].v);
		if(Q[i].op==2) vis[Q[i].v]=true;
	}
	for(int i=1;i<=m;i++)
		if(!vis[i]) Merge(e[i].x,e[i].y);
	for(int i=q;i>=1;i--)
	{
		if(Q[i].op==1) Q[i].v=find(Q[i].v);
		else
			Merge(e[Q[i].v].x,e[Q[i].v].y);
	}
	int last=0;
	for(int i=1;i<=n;i++)
		if(find(i)==i)
		{
			if(last) Merge(last,i),last=i;
			else last=i;
		}
	dfs(last);
	for(int i=1;i<=n;i++)
		change(1,1,n,dfn[i],mp(a[i],dfn[i]));
	for(int i=1;i<=q;i++)
		if(Q[i].op==1)
		{
			PII ans=query(1,1,n,dfn[Q[i].v],dfn[Q[i].v]+siz[Q[i].v]-1);
			printf("%d\n",ans.first);
			change(1,1,n,ans.second,mp(0,0));
		}
	return 0;
}

#pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pop_b pop_back
#define pf push_front
#define pop_f pop_front
#define mt make_tuple
#define eb emplace_back
#define sf(x) sizeof(x)
#define len(x) x.length()
#define sz(x) x.size()
#define fastio() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)

#define LB(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define UB(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
typedef long long ll;
typedef pair<ll,ll> ii;
typedef pair<int, int> pii;
typedef long double ld;
typedef vector<int> vi;
typedef vector<set<ll>> vset;
typedef vector<ll> vl;
typedef vector<ld> vd;
typedef deque<ll> dql;
typedef deque<int> dqi;
typedef unsigned long long ull;
typedef tuple<int,int,int> State;

#define error(args...) { string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args); }
void err(istream_iterator<string> it) {}
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args) {
	cerr << *it << " = " << a << ", ";
	err(++it, args...);
	cout<<"\n";
}

#define vmax(type)   std::numeric_limits<type>::max()
#define vmin(type)   std::numeric_limits<type>::min()
#define each(a,x) for( auto &a:(x))
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define repr(i, n) for (ll i = (n) - 1; i >= 0; i--)
#define rep2(i, l, r) for (ll i = (l); i < (r); i++)
#define rep2r(i, l, r) for (ll i = (r) - 1; i >= (l); i--)
#define range(a) a.begin(), a.end()
#define deb(x) cout<<#x<<" "<<x<<endl;
#define cinai(a, n) vi a(n); rep(i, n) { cin>>a[i]; }
#define cinal(a, n) vl a(n); rep(i, n) { cin>>a[i]; }
#define coutai(a, n) rep(i, n) { cout<<a[i]<<" "; } ent;
#define coutal(a, n) rep(i, n) { cout<<a[i]<<" "; } ent;
#define ent cout<<endl;
#define resize_vec(a) a.resize(unique(a.begin(), a.end()) - a.begin());
#define ms(dp, x) memset(dp, x, sf(dp))
#define endl '\n'

ll powm(ll a, ll b, ll mod) {
	ll res=1;
	while(b) {
		if(b&1)
			res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}

const ll mod = 1e9 + 7;
const ll N = 1000005;
const ll inf = 1e9;

int n, tin[N], tout[N];
int q, par[N], timer = 0, m, arr[N];
vi adj[N];
bool del[N];
pair<int, int> t[N<<2], query[N], edg[N];

int findPar(int x){
	if(x == par[x])
		return x;
	return par[x] = findPar(par[x]);
}

void unite(int a, int b){
	a = findPar(a);
	b = findPar(b);

	if(a == b)
		return;
	++n;
	par[a] = n;
	par[n] = n;
	par[b] = n;
	adj[n].pb(a);
	adj[n].pb(b);
}

void dfs(int v){
	tin[v] = ++timer;
	for(int to : adj[v])
		dfs(to);
	tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
	if (l > r || tl > r || tr < l) {
    	return mp(0, 0);
  	}

  	if (l <= tl && tr <= r) {
    	return t[v];
  	}

  	int mid = (tl + tr) >> 1;
  	int c1 = (v << 1), c2 = (c1 | 1);

  	return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void update(int v, int tl, int tr, int p, pii x) {
  	if (tl == tr) {
    	t[v] = x;
    	return;
  	}

  	int mid = (tl + tr) >> 1;
	int c1 = (v << 1), c2 = (c1 | 1);

  	if (p <= mid) {
    	update(c1, tl, mid, p, x);
  	}
  	else {
    	update(c2, mid + 1, tr, p, x);
  	}

  	t[v] = max(t[c1], t[c2]);
}

void solve()
{
	cin >> n >> m >> q;

	for(int i = 1; i <= n; i++)
		cin >> arr[i];

	for(int i = 1; i <= m; i++){
		del[i] = 0;
		cin >> edg[i].fi >> edg[i].se;
	}

	for(int i = 1; i <= q; i++){
		cin >> query[i].fi >> query[i].se;
		if(query[i].fi == 2)
			del[query[i].se] = 1;
	}

	for(int i = 1; i <= n; i++)
		par[i] = i;

	for(int i = 1; i <= m; i++){
		if(!del[i])
			unite(edg[i].fi, edg[i].se);
	}

	for(int i = q; i >= 1; i--){
		if(query[i].fi == 2){
			unite(edg[query[i].se].fi, edg[query[i].se].se);
		}else{
			query[i].se = findPar(query[i].se);
		}
	}

	for(int i = n; i >= 1; i--)
		if(par[i] == i)
			dfs(i);

	for(int i = 1; i <= n; i++){
		update(1, 1, n, tin[i], mp(arr[i], tin[i]));
	}

	for(int i = 1; i <= q; i++){
		int tp = query[i].fi;

		if(tp == 1){
			int v = query[i].se;
			pii tmp = segMax(1, 1, n, tin[v], tout[v]);

			if(tmp.fi == 0)
				cout<<0<<endl;
			else{
				cout<<tmp.fi<<endl;
				update(1, 1, n, tmp.se, mp(0, 0));
			}
		}
	}
}

signed main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cout << fixed << setprecision(15);

	int tc = 1;
	// cin>>tc;
	while(tc--)
	{
		solve();
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N=200005;
struct DSU
{
    vector<int> p;
    vector<int> sz;
    DSU(int n)
    {
        p.assign(n+1,0);
        for(int i=0;i<=n;i++) p[i]=i;
        sz.assign(n+1,1);
    }
    int find_set(int a)
    {
        if(a==p[a]) return a;
        else return p[a]=find_set(p[a]);
    }
    int merge_sets(int a,int b) //returns component with smaller size, or -1 if they are already connected
    {
        int origa=a;
        int origb=b;
        a=find_set(a);
        b=find_set(b);
        if(a==b) return -1;
        if(sz[a]<sz[b])
        {
            swap(a,b);
            swap(origa,origb);
        }
        p[b]=a;
        sz[a]+=sz[b];
        return origb;
    }
};

vector<array<int,2>> v[N];
vector<int> val(N,0);
vector<int> leader(N,0);
vector<set<int>> s(2*N);
int lidx=1;
int tnow=0;

void dfs1(int a,int l)
{
    leader[a]=l;
    s[l].insert(val[a]);
    for(auto [t,to]:v[a])
    {
        if(tnow>=t) break;
        if(leader[to]==0) dfs1(to,l);
    }
}

void dfs2(int a,int l,int r)
{
    leader[a]=l;
    if(val[a]!=0)
    {
        s[l].insert(val[a]);
        s[r].erase(val[a]);
    }
    for(auto [t,to]:v[a])
    {
        if(tnow>=t) break;
        if(leader[to]==r) dfs2(to,l,r);
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,q;
    cin >> n >> m >> q;
    vector<array<int,2>> edges(m+1,{0,0});
    DSU dsu(n);
    for(int i=1;i<=n;i++) cin >> val[i];
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin >> a >> b;
        edges[i]={a,b};
    }
    vector<bool> removed_edges(m+1,0);
    vector<array<int,2>> queries(q+1,{0,0});
    for(int i=1;i<=q;i++)
    {
        int t,a;
        cin >> t >> a;
        queries[i]={t,a};
        if(t==2) removed_edges[a]=1;
    }
    vector<int> disconnects(q+1,0); //0 if nothing is disconnected, the vertex with smaller current size otherwise
    for(int i=1;i<=m;i++)
    {
        if(removed_edges[i]==0)
        {
            auto [a,b]=edges[i];
            dsu.merge_sets(a,b);
            v[a].push_back({q+1,b});
            v[b].push_back({q+1,a});
        }
    }
    for(int i=q;i>=1;i--)
    {
        auto [t,a]=queries[i];
        if(t==1) continue;
        auto [c,d]=edges[a];
        int x=dsu.merge_sets(c,d);
        v[c].push_back({i,d});
        v[d].push_back({i,c});
        if(x!=-1) disconnects[i]=x;
    }
    for(int i=1;i<=n;i++) sort(v[i].begin(),v[i].end(),greater<array<int,2>>());
    for(int i=1;i<=n;i++)
    {
        if(leader[i]!=0) continue;
        dfs1(i,lidx++);
    }
    vector<bool> used(n+1,0);
    vector<int> h(n+1,0);
    for(int i=1;i<=n;i++) h[val[i]]=i;
    //set val[a]=0;
    for(int i=1;i<=q;i++)
    {
        tnow=i;
        auto [t,a]=queries[i];
        if(t==1)
        {
            int res=0;
            if(!s[leader[a]].empty())
            {
                int mx=(*s[leader[a]].rbegin());
                s[leader[a]].erase(mx);
                val[h[mx]]=0;
                res=mx;
            }
            cout << res << "\n";
        }
        else if(t==2)
        {
            int src=disconnects[i];
            if(src!=0) dfs2(src,lidx++,leader[src]);
        }
    }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int N=200005;
struct DSU
{
    vector<int> p;
    vector<int> sz;
    DSU(int n)
    {
        p.assign(n+1,0);
        for(int i=0;i<=n;i++) p[i]=i;
        sz.assign(n+1,1);
    }
    int find_set(int a)
    {
        if(a==p[a]) return a;
        else return p[a]=find_set(p[a]);
    }
    int merge_sets(int a,int b) //returns component with smaller size, or -1 if they are already connected
    {
        int origa=a;
        int origb=b;
        a=find_set(a);
        b=find_set(b);
        if(a==b) return -1;
        if(sz[a]<sz[b])
        {
            swap(a,b);
            swap(origa,origb);
        }
        p[b]=a;
        sz[a]+=sz[b];
        return origb;
    }
};

vector<set<int>> v(N);
vector<int> val(N,0);
vector<int> leader(N,0);
vector<set<int>> s(2*N);
int lidx=1;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,q;
    cin >> n >> m >> q;
    vector<array<int,2>> edges(m+1,{0,0});
    DSU dsu(n);
    for(int i=1;i<=n;i++) cin >> val[i];
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin >> a >> b;
        edges[i]={a,b};
        v[a].insert(b);
        v[b].insert(a);
    }
    vector<bool> removed_edges(m+1,0);
    vector<array<int,2>> queries(q+1,{0,0});
    for(int i=1;i<=q;i++)
    {
        int t,a;
        cin >> t >> a;
        queries[i]={t,a};
        if(t==2) removed_edges[a]=1;
    }
    vector<int> disconnects(q+1,0); //0 if nothing is disconnected, the vertex with smaller current size otherwise
    for(int i=1;i<=m;i++) if(removed_edges[i]==0) dsu.merge_sets(edges[i][0],edges[i][1]);
    for(int i=q;i>=1;i--)
    {
        auto [t,a]=queries[i];
        if(t==1) continue;
        int x=dsu.merge_sets(edges[a][0],edges[a][1]);
        if(x!=-1) disconnects[i]=x;
    }
    for(int i=1;i<=n;i++)
    {
        if(leader[i]!=0) continue;
        queue<int> z;
        z.push(i);
        int now=lidx++;
        leader[i]=now;
        s[now].insert(val[i]);
        while(!z.empty())
        {
            int a=z.front();
            z.pop();
            for(int to:v[a])
            {
                if(leader[to]!=0) continue;
                leader[to]=now;
                s[now].insert(val[to]);
                z.push(to);
            }
        }
    }
    vector<bool> used(n+1,0);
    vector<int> h(n+1,0);
    for(int i=1;i<=n;i++) h[val[i]]=i;
    //set val[a]=0;
    for(int i=1;i<=q;i++)
    {
        auto [t,a]=queries[i];
        if(t==1)
        {
            int res=0;
            if(!s[leader[a]].empty())
            {
                int mx=(*s[leader[a]].rbegin());
                s[leader[a]].erase(mx);
                val[h[mx]]=0;
                res=mx;
            }
            cout << res << "\n";
        }
        else if(t==2)
        {
            auto [x,y]=edges[a];
            v[x].erase(y);
            v[y].erase(x);
            int src=disconnects[i];
            if(src!=0)
            {
                queue<int> z;
                z.push(src);
                int prv=leader[src];
                int now=lidx++;
                leader[src]=now;
                if(val[src]!=0) s[prv].erase(val[src]);
                if(val[src]!=0) s[now].insert(val[src]);
                while(!z.empty())
                {
                    int e=z.front();
                    z.pop();
                    for(int to:v[e])
                    {
                        if(leader[to]==now) continue;
                        leader[to]=now;
                        z.push(to);
                        if(val[to]!=0) s[prv].erase(val[to]);
                        if(val[to]!=0) s[now].insert(val[to]);
                    }
                }
            }
        }
    }
    return 0;
}

// Nurstan Duisengaliev
// ASA KONKRETNO KATAIMASH
// MUKHA KONKRETNO KATAIMASH
// ADIL SEN KATAIABER, TEBE MOZHNO

/*#pragma GCC target ("avx2")
#pragma GCC optimize ("Ofast")
#pragma GCC optimize ("unroll-loops")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize("O3")*/

#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

#define ll long long
#define all(x) x.begin(), x.end()
#define in insert
#define mp make_pair
#define F first
#define S second
#define ppf pop_front
#define pb push_back
#define ppb pop_back
#define pf push_front
#define pii pair <int, int>
#define boost() ios_base::sync_with_stdio(0), cin.tie(0)
#define sz(x) (int)x.size()

using namespace std;
//using namespace __gnu_pbds;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

const int N = (int)4e6 + 123;
const int mod = (int)1e9 + 7;
const ll INF = (ll)1e18 + 1;
int n, m, Q;
int a[N], par[N];
pii edge[N], q[N];
bool del[N];
vector <int> g[N];
int get_par (int v) {
	if (par[v] == v) return v;
	return par[v] = get_par (par[v]);
}
void unite_sets (int v, int u) {
	v = get_par (v), u = get_par (u);
	if (v == u) return;
	n ++;
	par[v] = n;
	par[u] = n;
	par[n] = n;
	g[n].pb (v);
	g[n].pb (u);
}
int tin[N], tout[N], timer = 0;
pii d[N];
void update (int v, int l, int r, int pos, pii x) {
	if (l == r) {
		d[v] = x;
		return;
	}
	int mid = l + r >> 1;
	if (pos <= mid) update (v * 2, l, mid, pos, x);
	else update (v * 2 + 1, mid + 1, r, pos, x);
	if (d[v * 2].F <= d[v * 2 + 1].F) d[v] = d[v * 2 + 1];
	else d[v] = d[v * 2];
}
pii get (int v, int l, int r, int nl, int nr) {
	if (nl > r || l > nr) return mp (0, 0);
	if (nl <= l && r <= nr) return d[v];
	int mid = l + r >> 1;
	pii f = get (v * 2, l, mid, nl, nr), s = get (v * 2 + 1, mid + 1, r, nl, nr);
	if (f.F >= s.F) return f;
	else return s;
}
void dfs (int v) {
	tin[v] = ++ timer;
	update (1, 1, n, tin[v], mp (a[v], tin[v]));
	for (auto to : g[v]) {
		dfs (to);
	}
	tout[v] = timer;
}
void solve () {
	cin >> n >> m >> Q;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
		par[i] = i;
	}
	for (int i = 1; i <= m; i ++) {
		cin >> edge[i].F >> edge[i].S;
	}
	for (int i = 1; i <= Q; i ++) {
		int x, y;
		cin >> x >> y;
		q[i] = mp (x, y);
		if (x == 2) {
			del[y] = 1;
		}
	}
	for (int i = 1; i <= m; i ++) {
		if (!del[i]) unite_sets (edge[i].F, edge[i].S);
	}
	for (int i = Q; i >= 1; i --) {
		if (q[i].F == 1) {
			q[i].S = get_par (q[i].S);
		}
		else {
			unite_sets (edge[q[i].S].F, edge[q[i].S].S);
		}
	}
	for (int i = 1; i <= n; i ++) {
		if (par[i] == i) {
			dfs (i);
		}
	}
	for (int i = 1; i <= Q; i ++) {
		if (q[i].F == 1) {
			pii x = get (1, 1, n, tin[q[i].S], tout[q[i].S]);
			if (x.F != 0) update (1, 1, n, x.S, mp (0, 0));
			cout << x.F << '\n';
		}
	}
}

main () {
//	freopen (".in", "r", stdin);
//	freopen (".out", "w", stdout);
	boost ();
	int TT = 1;
// 	cin >> TT;
	while (TT --) {
		solve ();
	}
	return 0;
}

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct Tree
{
	#define lc x<<1
	#define rc x<<1|1
	#define mid ((l+r)>>1)
	int maxp[1600005],a[400005];
	void pushup(int x)
	{
		maxp[x]=a[maxp[lc]]>a[maxp[rc]]?maxp[lc]:maxp[rc];
	}
	void build(int x,int l,int r)
	{
		if(l==r)
		{
			maxp[x]=l;
			return;
		}
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(x);
	}
	int ask(int x,int l,int r,int from,int to)
	{
		if(l>=from&&r<=to)return maxp[x];
		int ans=from;
		if(from<=mid)
		{
			int p=ask(lc,l,mid,from,to);
			if(a[p]>=a[ans])ans=p;
		}
		if(to>mid)
		{
			int p=ask(rc,mid+1,r,from,to);
			if(a[p]>=a[ans])ans=p;
		}
		return ans;
	}
	void update(int x,int l,int r,int p)
	{
		if(l==r)
		{
			a[l]=0;
			return;
		}
		if(p<=mid)update(lc,l,mid,p);
		else update(rc,mid+1,r,p);
		pushup(x);
	}
}T;
struct Edge
{
	int u,v;
	int t;
}e[300005];
struct Query
{
	int type;
	int k;
}a[500005];
int n,m,q,tot,p[400005],t[400005],r[400005],pa[400005],anc[20][400005];
int child[400005][2];
bool cmp(Edge a,Edge b)
{
	return a.t>b.t;
}
int find(int x)
{
	return x==r[x]?x:r[x]=find(r[x]);
}
int ind,dfn[400005],size[400005];
void dfs(int node)
{
	dfn[node]=++ind;
	T.a[ind]=p[node];
	size[node]=1;
	if(child[node][0])dfs(child[node][0]);
	if(child[node][1])dfs(child[node][1]);
	size[node]+=size[child[node][0]]+size[child[node][1]];
}
void pre()
{
	for(int i=1;i<=tot;i++)anc[0][i]=pa[i];
	for(int i=1;i<20;i++)
	  for(int j=1;j<=tot;j++)
	    anc[i][j]=anc[i-1][anc[i-1][j]];
}
void ask(int node,int ti)
{
	for(int i=19;i>=0;i--)
	  if(t[anc[i][node]]>ti)
	    node=anc[i][node];
	int pos=T.ask(1,1,tot,dfn[node],dfn[node]+size[node]-1);
	printf("%d\n",T.a[pos]);
	T.update(1,1,tot,pos);
}
int main()
{
	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),e[i].t=q+1;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&a[i].type,&a[i].k);
		if(a[i].type==2)e[a[i].k].t=i;
	}
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=n;i++)r[i]=i,t[i]=q+1;
	tot=n;
	for(int i=1;i<=m;i++)
	{
		int u=e[i].u,v=e[i].v;
		if(find(u)==find(v))continue;
		pa[find(u)]=pa[find(v)]=++tot;
		child[tot][0]=find(u);
		child[tot][1]=find(v);
		r[tot]=r[find(u)]=r[find(v)]=tot;
		t[tot]=e[i].t;
	}
	for(int i=tot;i>=1;i--)
		if(!dfn[i])dfs(i);
	pre();
	T.build(1,1,tot);
	for(int i=1;i<=q;i++)
	{
		if(a[i].type==1)
		  ask(a[i].k,i);
	}
	return 0;
}

// chrono::system_clock::now().time_since_epoch().count()
#include<bits/stdc++.h>

#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(), (x).end()
#define debug(x) cerr << #x << " = " << x << endl;

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = (int)5e5 + 5;
const int MAXM = (int)3e5 + 5;
const int MAXQ = (int)5e5 + 5;

pii e[MAXM], que[MAXQ], t[MAXN << 2];
vector<int> adj[MAXN];
int tin[MAXN], tout[MAXN], timer;
int par[MAXN], arr[MAXN];
bool del[MAXM];
int n, m, q;

int getPar(int x) {
	if (x == par[x]) {
		return x;
	}

	return par[x] = getPar(par[x]);
}

void uni(int a, int b) {
	a = getPar(a);
	b = getPar(b);

	if (a == b) {
		return;
	}

	++n;
	par[n] = n;
	par[a] = n;
	par[b] = n;
	adj[n].pb(a);
	adj[n].pb(b);
}

void dfs(int v) {
	tin[v] = ++timer;

	for (int to : adj[v]) {
		dfs(to);
	}

	tout[v] = timer;
}

pii segMax(int v, int tl, int tr, int l, int r) {
	if (l > r || tl > r || tr < l) {
		return mp(0, 0);
	}

	if (l <= tl && tr <= r) {
		return t[v];
	}

	int mid = (tl + tr) >> 1;
	int c1 = (v << 1), c2 = (c1 | 1);

	return max(segMax(c1, tl, mid, l, r), segMax(c2, mid + 1, tr, l, r));
}

void updPos(int v, int tl, int tr, int p, pii x) {
	if (tl == tr) {
		t[v] = x;
		return;
	}

	int mid = (tl + tr) >> 1;
	int c1 = (v << 1), c2 = (c1 | 1);

	if (p <= mid) {
		updPos(c1, tl, mid, p, x);
	}
	else {
		updPos(c2, mid + 1, tr, p, x);
	}

	t[v] = max(t[c1], t[c2]);
}

void solve() {
	scanf("%d %d %d", &n, &m, &q);

	for (int i = 1; i <= n; ++i) {
		scanf("%d", &arr[i]);
	}

	for (int i = 1; i <= m; ++i) {
		int u, v;
		scanf("%d %d", &u, &v);
		e[i] = mp(u, v);
	}

	for (int i = 1; i <= q; ++i) {
		int a, b;
		scanf("%d %d", &a, &b);
		que[i] = mp(a, b);

		if (a == 2) {
			del[b] = 1;
		}
	}

	for (int i = 1; i <= n; ++i) {
		par[i] = i;
	}

	for (int i = 1; i <= m; ++i) {
		if (!del[i]) {
			uni(e[i].fi, e[i].se);
		}
	}

	for (int i = q; i > 0; --i) {
		int tp = que[i].fi;

		if (tp == 2) {
			int id = que[i].se;
			uni(e[id].fi, e[id].se);
		}
		else {
			que[i].se = getPar(que[i].se);
		}
	}

	for (int i = 1; i <= n; ++i) {
		if (getPar(i) == i) {
			dfs(i);
		}
	}

	for (int i = 1; i <= n; ++i) {
		updPos(1, 1, n, tin[i], mp(arr[i], tin[i]));
	}

	for (int i = 1; i <= q; ++i) {
		int tp = que[i].fi;

		if (tp == 1) {
			int v = que[i].se;
			pii tmp = segMax(1, 1, n, tin[v], tout[v]);

			if (tmp.fi == 0) {
				printf("0\n");
			}
			else {
				printf("%d\n", tmp.fi);
				updPos(1, 1, n, tmp.se, mp(0, 0));
			}
		}
	}
}

int main() {
	int tt = 1;

	while (tt--) {
		solve();
	}

	return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define f first
#define s second
using namespace std;
const int mxn=2e5+5;
const int mxm=3e5+5;
const int mxq=5e5+5;

const int inf=1e9;
int p[mxn];
int L[mxm],R[mxm];
bool usd[mxm];
int tp[mxq],id[mxq];

struct reachability_tree {
	int parent[mxn];
	int sz[mxn];
	int in[mxn],out[mxn],id[mxn];
	int pc[mxn];
	vector<int> g[mxn];
	vector<int> w[mxn];
	int T=0;

	void init(int n) {
		for(int i=1;i<=n;i++) {
			parent[i] = i;
			sz[i] = 1;
		}
	}

	int findrep(int u) {
		return parent[u] == u ? u : findrep(parent[u]);
	}

	void unite(int u,int v,int cst) {
		u=findrep(u);
		v=findrep(v);
		if(u == v) return;

		if(sz[u] > sz[v]) swap(u,v);

		parent[u] = v;
		sz[v] += sz[u];
		g[v].push_back(u);
		w[v].push_back(cst);
		pc[u] = cst;

	}
	void dfs(int u) {
		in[u] = ++T;
		id[T] = u;
		for(int v : g[u]) {
			dfs(v);
		}
		out[u] = T;
	}

	pii range(int u, int tm) {
		while(parent[u] != u && pc[u] >= tm) u = parent[u];

		int p = upper_bound(w[u].begin(),w[u].end(),tm,[](int a,int b) {
			return a > b;
		}) - w[u].begin();

		if(p == 0) {
			return {in[u], in[u]};
		}

		int v = g[u][p-1];
		return {in[u],out[v]};
	}

} rt ;

struct segtree {
	pii tree[4*mxn];

	void update(int node,int b,int e,int p,int v) {
		if(e<p || b>p) return;
		if(b == e) {
			tree[node] = {v,b};
			return;
		}

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		update(left,b,mid,p,v);
		update(right,mid+1,e,p,v);
		tree[node]=max(tree[left],tree[right]);
	}

	pii query(int node,int b,int e,int l,int r) {
		if(b > r || e < l) return {0,0};

		if(b >=l && e <=r ) return tree[node];

		int mid=b+e>>1;
		int left=node<<1;
		int right=left|1;

		return max(query(left,b,mid,l,r) , query(right,mid+1,e,l,r));

	}
} st;

int main() {
	int n,m,q;
	cin>>n>>m>>q;

	for(int i=1;i<=n;i++) {
		scanf("%d",&p[i]);
	}

	for(int i=1;i<=m;i++) {
		scanf("%d%d",&L[i], &R[i]);
	}

	for(int i=1;i<=q;i++) {
		scanf("%d %d", &tp[i], &id[i]);

		if(tp[i]==2) usd[id[i]] = true;
	}
	rt.init(n);

	for(int i=1;i<=m;i++) {
		if(!usd[i]) rt.unite(L[i],R[i],inf);
	}

	for(int i=q;i>0;i--) {
		if(tp[i] == 2) rt.unite(L[id[i]],R[id[i]],i);
	}

	for(int i=1;i<=n;i++) {
	    if(rt.findrep(i) == i) {
	        rt.dfs(i);
	    }
	}

	for(int i=1;i<=n;i++) {
		st.update(1,1,n,rt.in[i],p[i]);
	}
	bool dn[mxn]={};

	for(int i=1;i<=q;i++) {
		if(tp[i] == 1) {
			pii rg= rt.range(id[i],i);
			pii x = st.query(1,1,n,rg.f,rg.s);

			if(x.f == 0) {
				printf("0\n");
			} else {
				printf("%d\n", x.f);
				if(dn[x.s]) continue;
				st.update(1,1,n,x.s,0);
			}
		}
	}

}

#include <bits/stdc++.h>

int32_t main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif
    int32_t n, m, q;
    scanf("%d%d%d", &n, &m, &q);
    std::vector<int32_t> a(n);
    for (int32_t i = 0; i < n; i++)
        scanf("%d", &a[i]);
    std::vector<std::pair<int32_t, int32_t>> edges(m);
    for (int32_t i = 0; i < m; i++) {
        scanf("%d%d", &edges[i].first, &edges[i].second);
        --edges[i].first;
        --edges[i].second;
    }
    std::vector<bool> removed(m);
    std::vector<std::pair<int32_t, int32_t>> queries(q);
    for (int32_t i = 0; i < q; i++) {
        scanf("%d%d", &queries[i].first, &queries[i].second);
        --queries[i].second;
        if (queries[i].first == 2)
            removed[queries[i].second] = true;
    }
    std::vector<int32_t> parent(n, -1);
    auto find = [&](int32_t x) {
        while (0 <= parent[x]) x = parent[x];
        return x;
    };
    std::vector<std::vector<int32_t>> adj(n);
    auto merge = [&](int32_t u, int32_t v) {
        u = find(u), v = find(v);
        if (u == v) return;
        if (parent[u] < parent[v])
            std::swap(u, v);
        parent[v] += parent[u];
        adj[v].push_back(u);
        parent[u] = v;
    };
    for (int32_t i = 0; i < m; i++) {
        if (removed[i]) continue;
        merge(edges[i].first, edges[i].second);
    }
    std::vector<int32_t> children;
    for (int32_t i = q; i --> 0;) {
        if (queries[i].first == 1) {
            int32_t x = find(queries[i].second);
            queries[i].second = x;
            children.push_back(adj[x].empty() ? -1 : adj[x].back());
        } else {
            auto edge = edges[queries[i].second];
            merge(edge.first, edge.second);
        }
    }
    std::reverse(children.begin(), children.end());
    std::vector<std::pair<int32_t, int32_t>> tree;
    tree.reserve(n + n);
    tree.resize(n);
    int32_t stamp = 0;
    std::vector<int32_t> left(n), right(n);
    std::function<void(int32_t)> euler = [&](int32_t u) {
        tree.emplace_back(a[u], stamp);
        left[u] = stamp++;
        for (int32_t v : adj[u])
            euler(v);
        right[u] = stamp;
    };
    for (int32_t i = 0; i < n; i++) {
        if (find(i) == i) euler(i);
    }
    for (int32_t i = n; i --> 1;)
        tree[i] = std::max(tree[i + i], tree[i + i + 1]);
    for (int32_t i = 0, j = 0; i < q; i++) {
        if (queries[i].first == 2) continue;
        int32_t l = left[queries[i].second];
        int32_t r = children[j++];
        r = (r < 0 ? l + 1 : right[r]);
        std::pair<int32_t, int32_t> res;
        for (l += n, r += n; l < r; l /= 2, r /= 2) {
            if (l & 1) res = std::max(res, tree[l++]);
            if (r & 1) res = std::max(tree[--r], res);
        }
        printf("%d\n", res.first);
        int32_t x = res.second + n;
        tree[x].first = 0;
        while (x /= 2)
            tree[x] = std::max(tree[x + x], tree[x + x + 1]);
    }
    return 0;
}

#include <cstdio>
#include <vector>
using namespace std;
const int MAXN=500005;
int n, m, q, num, dfc;
int a[MAXN], w[MAXN];
int u[MAXN], v[MAXN], f[MAXN];
int opt[MAXN], ob[MAXN], p[MAXN];
bool cut[MAXN];
int op[MAXN], cl[MAXN];
vector<int> G[MAXN];
int getf(int x)
{
	if (x==f[x]) return x;
	return f[x]=getf(f[x]);
}
void merge(int u, int v)
{
	int x=getf(u), y=getf(v);
	if (x!=y)
	{
		f[x]=f[y]=++num;
		G[num].push_back(x);
		G[num].push_back(y);
	}
}
void DFS(int u)
{
	op[u]=++dfc;
	for (int v: G[u]) DFS(v);
	cl[u]=dfc;
}
namespace SGT
{
	struct Node
	{
		int l, r;
		pair<int, int> val;
	} tr[4*MAXN];
#define lc (o<<1)
#define rc (o<<1|1)
	void pushup(int o)
	{
		tr[o].val=max(tr[lc].val, tr[rc].val);
	}
	void build(int o, int l, int r, int* a)
	{
		tr[o].l=l, tr[o].r=r;
		if (l==r) return tr[o].val=make_pair(a[l], l), void();
		int mid=(l+r)>>1;
		build(lc, l, mid, a);
		build(rc, mid+1, r, a);
		pushup(o);
	}
	pair<int, int> query(int o, int l, int r)
	{
		if (tr[o].l>r||tr[o].r<l) return make_pair(0, 0);
		if (l<=tr[o].l&&tr[o].r<=r) return tr[o].val;
		return max(query(lc, l, r), query(rc, l, r));
	}
	void modify(int o, int p)
	{
		if (tr[o].l==tr[o].r) return tr[o].val.first=0, void();
		int mid=(tr[o].l+tr[o].r)>>1;
		if (p<=mid) modify(lc, p);
		else modify(rc, p);
		pushup(o);
	}
#undef lc
#undef rc
}
int main()
{
//	freopen("D.in", "r", stdin);
//	freopen("D.out", "w", stdout);
	scanf("%d%d%d", &n, &m, &q);
	for (int i=1; i<=n; i++) scanf("%d", &a[i]);
	for (int i=1; i<=m; i++) scanf("%d%d", &u[i], &v[i]);
	for (int i=1; i<=n+m; i++) f[i]=i;
	for (int i=1; i<=q; i++)
	{
		scanf("%d%d", &opt[i], &ob[i]);
		if (opt[i]==2) cut[ob[i]]=1;
	}
	num=n;
	for (int i=1; i<=m; i++)
		if (!cut[i]) merge(u[i], v[i]);
	for (int i=q; i>=1; i--)
		if (opt[i]==1) p[i]=getf(ob[i]);
		else merge(u[ob[i]], v[ob[i]]);
	for (int i=1; i<=num; i++)
		if (getf(i)==i) DFS(i);
	for (int i=1; i<=num; i++) w[op[i]]=a[i];
	SGT::build(1, 1, num, w);
	for (int i=1; i<=q; i++)
		if (opt[i]==1)
		{
			auto ret=SGT::query(1, op[p[i]], cl[p[i]]);
			printf("%d\n", ret.first);
			SGT::modify(1, ret.second);
		}
	return 0;
}

#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <deque>
#include <complex>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <ctime>
#include <iterator>
#include <bitset>
#include <numeric>
#include <list>
#include <iomanip>
#include <cassert>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <queue>
using namespace std;
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define div div228
#define prev prev228
#define free free228
#define close close228
typedef long double ld;
const int BINF = 9e18, LINF = 2e9, mod = 1e9 + 7, P = 179, Q = 1791791791;
typedef long long ll;

const int MAXN = 6e5 + 6, MAXQ = 1e6 + 6;
int a[MAXN], b[MAXN], p[MAXN];
list<int> cmp[MAXN];
int par[MAXN];
int t[MAXQ], f[MAXQ];
bool ban[MAXN];
int sep[MAXN];
int pos[MAXN], who[MAXN];
int get(int v) {
	if (par[v] == v)
		return v;
	return par[v] = get(par[v]);
}
int merge(int v, int u) {
	v = get(v), u = get(u);
	if (v == u)
		return -1;
	par[u] = v;
	int ans = *cmp[u].begin();
	cmp[v].splice(cmp[v].end(), cmp[u]);
	return ans;
}
pair<int, int> tt[4 * MAXN];
void build(int v, int tl, int tr) {
	if (tl == tr) {
		int val = p[who[tl]];
		tt[v] = {val, who[tl]};
	} else {
		int tm = (tl + tr) / 2;
		build(v << 1, tl, tm);
		build(v << 1 ^ 1, tm + 1, tr);
		tt[v] = max(tt[v << 1], tt[v << 1 ^ 1]);
	}
}
pair<int, int> get(int v, int tl, int tr, int l, int r) {
	if (l > tr || tl > r)
		return {-1, -1};
	if (l <= tl && tr <= r)
		return tt[v];
	int tm = (tl + tr) / 2;
	return max(get(v << 1, tl, tm, l, r), get(v << 1 ^ 1, tm + 1, tr, l, r));
}
void upd(int v, int tl, int tr, int p, int x) {
	if (tl == tr)
		tt[v] = {x, who[tl]};
	else {
		int tm = (tl + tr) / 2;
		if (p <= tm)
			upd(v << 1, tl, tm, p, x);
		else
			upd(v << 1 ^ 1, tm + 1, tr, p, x);
		tt[v] = max(tt[v << 1], tt[v << 1 ^ 1]);
	}
}
void solve() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 0; i < n; ++i)
    	cin >> p[i], par[i] = i, cmp[i].push_back(i);
    for (int i = 0; i < m; ++i) {
  		cin >> a[i] >> b[i];
  		--a[i], --b[i];
    }
    for (int i = 0; i < q; ++i) {
    	cin >> t[i] >> f[i];
    	--f[i];
    }
    for (int i = q - 1; i >= 0; --i)
    	if (t[i] == 2)
    		ban[f[i]] = 1;
    for (int i = 0; i < m; ++i)
    	if (!ban[i])
    		merge(a[i], b[i]);
    for (int i = q - 1; i >= 0; --i)
    	if (t[i] == 2)
    		sep[i] = merge(a[f[i]], b[f[i]]);
    int ptr = 0;
    set<pair<int, int>> segs;
    for (int i = 0; i < n; ++i)
    	if (par[i] == i) {
    		int l = ptr;
    		for (int v : cmp[i]) {
    			who[ptr] = v;
    			pos[v] = ptr++;
    		}
    		int r = ptr - 1;

    		segs.insert({l, r});
    	}
    build(1, 0, n - 1);
    /*cout << "#" << ptr << endl;
    cout << "=====\n";
    for (auto p : segs)
    	cout << p.x << "; " << p.y << endl;
    cout << "=====\n";*/
    for (int i = 0; i < q; ++i) {
    	if (t[i] == 2) {
    		if (sep[i] != -1) {
    			int m = pos[sep[i]];
    			auto it = segs.lower_bound({m, 1e9});
    			--it;
    			int l = it->x;
    			int r = it->y;
    			segs.erase(it);
    			segs.insert({l, m - 1});
    			segs.insert({m, r});
    		}
    	} else {
    		int v = f[i];
    		auto it = segs.lower_bound({pos[v], 1e9});
			--it;
			int l = it->x;
			int r = it->y;
			pair<int, int> pr = get(1, 0, n - 1, l, r);
			upd(1, 0, n - 1, pos[pr.second], 0);
			cout << pr.first << "\n";
    	}
    }
    return;
}
signed main() {
	//freopen("in.txt", "r", stdin);
    ios_base::sync_with_stdio(false);
    //cout.precision(40);

    int t = 1;
    //cin >> t;
    for (int i = 0; i < t; ++i)
        solve();

    return 0;
}
/*

10 5 15
1 2 3 4 5 6 7 8 9 10
1 2
3 4
5 6
7 8
9 10
1 1
2 1
1 1
1 3
2 2
1 3
1 5
2 3
1 5
1 7
2 4
1 8
1 9
2 5
1 10
*/

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e6+100;

int n,m,q;

struct Qu
{
	int op,x;
}qu[N];

struct Edge
{
	int u,v,w;
	bool operator<(const Edge& t)const
	{
		return w<t.w;
	}
}edge[N];

struct Max
{
	int val,pos;
	Max(){}
	Max(int val,int pos):val(val),pos(pos){}
	static Max inf()
	{
		return Max(-0x3f3f3f3f,0);
	}
	bool operator<(const Max& t)const
	{
		return val<t.val;
	}
};

struct Node
{
	int l,r;
	Max mmax;
}tree[N<<2];

int a[N],f[N],val[N],dp[N][25],L[N],R[N],id[N],tot;

vector<int>node[N];
/*线段树*/
void pushup(int k)
{
	tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);
}

void build(int k,int l,int r)
{
	tree[k].l=l;
	tree[k].r=r;
	if(l==r)
	{
		tree[k].mmax.val=a[id[l]];
		tree[k].mmax.pos=l;
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}

void update(int k,int pos)
{
	if(tree[k].l==tree[k].r)
	{
		tree[k].mmax.val=0;
		return;
	}
	int mid=tree[k].l+tree[k].r>>1;
	if(pos<=mid)
		update(k<<1,pos);
	else
		update(k<<1|1,pos);
	pushup(k);
}

Max query(int k,int l,int r)
{
	if(tree[k].l>r||tree[k].r<l)
		return Max::inf();
	if(tree[k].l>=l&&tree[k].r<=r)
		return tree[k].mmax;
	return max(query(k<<1,l,r),query(k<<1|1,l,r));
}
/*线段树*/
/*dfs序+树上倍增*/
void dfs(int u,int fa)
{
	dp[u][0]=fa;
	for(int i=1;i<=20;i++)
		dp[u][i]=dp[dp[u][i-1]][i-1];
	L[u]=++tot;
	id[tot]=u;
	for(auto v:node[u])
		dfs(v,u);
	R[u]=tot;
}

int get_pos(int u,int up)//树上倍增找满足的祖先
{
	for(int i=20;i>=0;i--)
		if(dp[u][i]!=0&&val[dp[u][i]]<=up)
			u=dp[u][i];
	return u;
}
/*dfs序+树上倍增*/
/*并查集+克鲁斯卡尔重构树*/
int find(int x)
{
	return f[x]==x?x:f[x]=find(f[x]);
}

int Ex_Kruskal()
{
	for(int i=1;i<=n<<1;i++)
		f[i]=i;
	int index=n;
	sort(edge+1,edge+1+m);
	for(int i=1;i<=m;i++)
	{
		int xx=find(edge[i].u),yy=find(edge[i].v);
		if(xx!=yy)
		{
			f[xx]=f[yy]=++index;
			val[index]=edge[i].w;
			node[index].push_back(xx);
			node[index].push_back(yy);
		}
	}
	int last=1;
	for(int i=1;i<=n;i++)
	{
		int xx=find(last),yy=find(i);
		if(xx!=yy)
		{
			f[xx]=f[yy]=++index;
			val[index]=inf;
			node[index].push_back(xx);
			node[index].push_back(yy);
			last=index;
		}
	}
	return index;
}
/*并查集+克鲁斯卡尔重构树*/
int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&edge[i].u,&edge[i].v);
		edge[i].w=0;
	}
	int val=inf;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&qu[i].op,&qu[i].x);
		if(qu[i].op==2)
			edge[qu[i].x].w=--val;
	}
	int root=Ex_Kruskal();
	dfs(root,0);
	build(1,1,root);
	val=inf-1;
	for(int i=1;i<=q;i++)
	{
		if(qu[i].op==1)
		{
			int x=get_pos(qu[i].x,val);
			Max ans=query(1,L[x],R[x]);
			printf("%d\n",ans.val);
			update(1,ans.pos);
		}
		else
			val--;
	}

    return 0;
}

#include<bits/stdc++.h>
using namespace std;

#define fs first
#define sc second
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
#define pb push_back
#define fastio ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define MP make_pair
#define sqr(x) ((x) * (x))
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const int N = 5e5 + 100, INF = 1e9;
vector<int> g[N];
int par[N], tin[N], tout[N], val[N];
pair<int, int> t[4 * N];
int cur_size, timer = 0;

int get(int v) {
    if (v == par[v]) {
        return v;
    }
    return par[v] = get(par[v]);
}

void unite(int a, int b) {
    a = get(a);
    b = get(b);
    if (a == b) {
        return;
    }
    int v = cur_size++;

    g[v].pb(a);
    g[v].pb(b);
    par[a] = par[b] = v;
}

void dfs(int v) {
    tin[v] = timer++;
    for (auto u : g[v]) {
        dfs(u);
    }
    tout[v] = timer;
}

void upd(int v, int l, int r, int pos, pair<int, int> x) {
    if (l + 1 == r) {
        t[v] = x;
        return;
    }
    int mid = (l + r) / 2;
    if (pos < mid) upd(v * 2 + 1, l, mid, pos, x);
    else upd(v * 2 + 2, mid, r, pos, x);
    t[v] = max(t[v * 2 + 1], t[v * 2 + 2]);
}

pair<int, int> qu(int v, int l, int r, int ql, int qr) {
    if (qr <= l || r <= ql) return {-INF, -INF};
    if (ql <= l && r <= qr) return t[v];
    int mid = (l + r) / 2;
    return max(qu(v * 2 + 1, l, mid, ql, qr), qu(v * 2 + 2, mid, r, ql, qr));
}

signed main() {
    fastio;
    #ifdef FlameDragon
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif

    for (int i = 0; i < N; i++) {
        par[i] = i;
    }

    int n, m, q;
    cin >> n >> m >> q;
    cur_size = n;
    vector<pair<int, int>> queries(q);
    vector<pair<int, int>> edges(m);
    vector<int> deleted(m);
    for (int i = 0; i < n; i++) {
        cin >> val[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> edges[i].fs >> edges[i].sc;
        edges[i].fs--; edges[i].sc--;
    }

    for (int i = 0; i < q; i++) {
        int type, id;
        cin >> type >> id;
        id--;
        if (type == 2) deleted[id] = 1;
        queries[i] = {type, id};
    }
    for (int i = 0; i < m; i++) {
        if (!deleted[i]) unite(edges[i].fs, edges[i].sc);
    }

    for (int i = q - 1; i >= 0; i--) {
        int type = queries[i].fs;
        if (type == 1) {
            queries[i].sc = get(queries[i].sc);
        } else {
            int id = queries[i].sc;
            unite(edges[id].fs, edges[id].sc);
        }
    }
    for (int i = 0; i < cur_size; i++) {
        if (par[i] == i) {
            dfs(i);
        }
    }

    for (int i = 0; i < cur_size; i++) {
        upd(0, 0, timer, tin[i], {val[i], i});
    }

    for (int i = 0; i < q; i++) {
        int type = queries[i].fs;
        // cout << 'f';
        if (type == 2) continue;
        int v = queries[i].sc;
        // cout << tin[v] << ' ' << tout[v] << endl;
        auto ans = qu(0, 0, timer, tin[v], tout[v]);
        cout << ans.fs << '\n';
        if (ans.fs != 0) {
            int u = ans.sc;
            upd(0, 0, timer, tin[u], {0, 0});
        }
    }
    // cout << 'f';
}

/*mjytxdy!*/
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define fir first
#define sec second
#define all(x) x.begin(),x.end()
#define size(x) ((int)x.size())
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
#define inl inline
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,r,l) for(int i=(r);i>=(l);i--)
#define trv(i,u) for(int i=head[u];i;i=e[i].next)
#define lb(x) ((x)&(-(x)))
#define lson rt<<1
#define rson rt<<1|1
#define debug(x) cout<<#x":"<<x<<'\n'
#define myput puts("QaQ")
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
typedef long long ll;
template<class T>inl bool ylmin(T &a,T b){return a<b?0:(a=b,1);}
template<class T>inl bool ylmax(T &a,T b){return a>b?0:(a=b,1);}
template<class T>inl T abs(T x){return x<0?-x:x;}
inl char read(){
	static const int IO_LEN=1024*1024;
	static char buf[IO_LEN],*ioh,*iot;
	if(ioh==iot){
		iot=(ioh=buf)+fread(buf,1,IO_LEN,stdin);
		if(ioh==iot) return -1;
	}
	return *ioh++;
}
template<class T>inl void read(T &x){
	static int iosig;static char ioc;
	for(iosig=0,ioc=read();!isdigit(ioc);ioc=read()) if(ioc=='-') iosig=1;
	for(x=0;isdigit(ioc);ioc=read())x=(x<<1)+(x<<3)+(ioc^'0');
	if(iosig) x=-x;
}
const int MAXN = 5e5+10;
int n,m,Q,p[MAXN],rev[MAXN],is[MAXN];
int Nodecnt,ls[MAXN],rs[MAXN];
int top[MAXN];
struct Edge{
	int u,v;
}e[MAXN];
struct que{
	int opt,x;
}q[MAXN];
namespace ufs{
	int fa[MAXN];
	inl void clear(){
		rep(i,1,n<<1) fa[i]=i;
	}
	inl int find(int x){
		return fa[x]==x?x:fa[x]=find(fa[x]);
	}
}
int dfs_time,L[MAXN],R[MAXN];
inl void dfs(int u){
	if(u<=n) L[u]=R[u]=++dfs_time,rev[dfs_time]=p[u];
	else {
		//cout<<u<<":"<<ls[u]<<' '<<rs[u]<<'\n';
		L[u]=dfs_time+1;
		dfs(ls[u]),dfs(rs[u]);
		R[u]=dfs_time;
	}
}
namespace seg{
	int Max[MAXN<<1],pos[MAXN<<1];
	inl void pushup(int rt){
		if(Max[lson]<Max[rson]) Max[rt]=Max[rson],pos[rt]=pos[rson];
		else Max[rt]=Max[lson],pos[rt]=pos[lson];
	}
	inl void update(int rt,int l,int r,int k){
		if(l==r){
			Max[rt]=0;
			return ;
		}
		int mid=l+r>>1;
		if(k<=mid) update(lson,l,mid,k);
		else update(rson,mid+1,r,k);
		pushup(rt);
	}
	inl pii query(int rt,int l,int r,int L,int R){
		if(l>=L && r<=R) return {Max[rt],pos[rt]};
		int mid=l+r>>1;
		if(R<=mid) return query(lson,l,mid,L,R);
		else if(L>mid) return query(rson,mid+1,r,L,R);
		else return max(query(lson,l,mid,L,R),query(rson,mid+1,r,L,R));
	}
	inl void build(int rt,int l,int r){
		if(l==r){
			pos[rt]=l;
			Max[rt]=rev[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid),build(rson,mid+1,r);
		pushup(rt);
	}
}
int main(){
//	freopen("in.txt","r",stdin);
	read(n),read(m),read(Q);Nodecnt=n;
	rep(i,1,n) read(p[i]);
	rep(i,1,m) read(e[i].u),read(e[i].v);
	rep(i,1,Q) read(q[i].opt),read(q[i].x);
	rep(i,1,Q) if(q[i].opt==2) is[q[i].x]=1;
	ufs::clear();
	rep(i,1,m){
		if(!is[i]) {
			int x=ufs::find(e[i].u),y=ufs::find(e[i].v);
			//cout<<e[i].u<<' '<<e[i].v<<'\n';
			if(x==y) continue;
			ufs::fa[x]=ufs::fa[y]=++Nodecnt;
			ls[Nodecnt]=x,rs[Nodecnt]=y;
		}
	}
	per(i,Q,1){
		if(q[i].opt==1){
			int x=ufs::find(q[i].x);
			top[i]=x;
		}
		if(q[i].opt==2){
			int x=ufs::find(e[q[i].x].u),y=ufs::find(e[q[i].x].v);
			//cout<<e[q[i].x].u<<' '<<e[q[i].x].v<<'\n';
			if(x==y) continue;
			ufs::fa[x]=ufs::fa[y]=++Nodecnt;
			ls[Nodecnt]=x,rs[Nodecnt]=y;
		}
	}
	int last=0;
	rep(i,1,Nodecnt) {
		if(ufs::find(i)==i) {
			if(last){
				ufs::fa[i]=ufs::fa[last]=++Nodecnt;
				ls[Nodecnt]=i,rs[Nodecnt]=last;
				last=0;
			}
			else last=i;
		}
	}
	dfs(Nodecnt);
	seg::build(1,1,n);
	rep(i,1,Q){
		if(q[i].opt==1){
			//cout<<top[i]<<":";
			pii Max=seg::query(1,1,n,L[top[i]],R[top[i]]);
			printf("%d\n",Max.fir);
			seg::update(1,1,n,Max.sec);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
int n, m, q, ex[300011], ey[300011];
struct oper {
	int opt, s, sma, big;
	bool tree;
} a[500011];
int p[200011], siz[200011], fa[200011], belong[200011];
vector <int> h[200011]; //注意:因为p[i]为1~n的一个排列，所以vector中存储的是数，不是下标
bool del[300011], used[200011];
int find(int w) {
	if(fa[w] == w) return w;
	return find(fa[w]);
}
int query(int w) {
	while(h[w].size() && (belong[h[w].back()] != w || used[h[w].back()])) h[w].pop_back();
	if(!h[w].size()) return 0;
	int ret = h[w].back();
	h[w].pop_back(); used[ret] = 1;
	return ret;
}
int main() {
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &p[i]); fa[i] = i;
		h[i].push_back(p[i]); siz[i] = 1;
	}
	for(int i = 1; i <= m; i++)
		scanf("%d%d", &ex[i], &ey[i]);
	for(int i = 1; i <= q; i++) {
		scanf("%d%d", &a[i].opt, &a[i].s);
		if(a[i].opt == 2) del[a[i].s] = 1;
		a[i].tree = 0;
	}
	for(int i = 1; i <= m; i++) {
		if(del[i]) continue;
		int fx = find(ex[i]), fy = find(ey[i]);
		if(fx == fy) continue;
		if(siz[fx] < siz[fy]) swap(fx, fy);
		siz[fx] += siz[fy]; fa[fy] = fx;
		for(int j = 0; j < (int)h[fy].size(); j++)
			h[fx].push_back(h[fy][j]);
	}
	for(int i = q; i >= 1; i--) {
		if(a[i].opt == 2) {
			int fx = find(ex[a[i].s]), fy = find(ey[a[i].s]);
			if(fx == fy) continue;
			if(siz[fx] < siz[fy]) swap(fx, fy);
			a[i].big = fx; a[i].sma = fy;
			fa[fy] = fx; siz[fx] += siz[fy];
			for(int j = 0; j < (int)h[fy].size(); j++)
				h[fx].push_back(h[fy][j]);
			a[i].tree = 1;
		}
	}
	for(int i = 1; i <= n; i++) {
		sort(h[i].begin(), h[i].end());
		belong[p[i]] = find(i);
	}
	for(int i = 1; i <= q; i++) {
		if(a[i].opt == 1) printf("%d\n", query(find(a[i].s)));
		else if(a[i].tree) {
			for(int j = 0; j < (int)h[a[i].sma].size(); j++)
				belong[h[a[i].sma][j]] = a[i].sma;
			fa[a[i].sma] = a[i].sma;
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

#ifdef NeverBeRed
#include "debug.h"
#else
#define debug(...) 9715
#endif
typedef long long ll;
typedef long double ld;
typedef complex<ld> point;
#define F first
#define S second

template<class node>
struct link_cut_tree
{
	bool connected(node* u, node* v) { return lca(u, v) != NULL; }

	int depth(node* u) { access(u); return get_sz(u->ch[0]); }

	node* get_root(node* u) // get root of LCT component
	{
		access(u);
		while (u->ch[0]) u = u->ch[0], u->push();
		return access(u), u;
	}

	node* ancestor(node* u, int k) // get k-th parent on path to root
	{
		k = depth(u) - k;
		assert(k >= 0);
		for (; ; u->push())
		{
			int sz = get_sz(u->ch[0]);
			if (sz == k) return access(u), u;
			if (sz < k) k -= sz+1, u = u->ch[1];
			else u = u->ch[0];
		}
		assert(0);
	}

	node* lca(node* u, node* v)
	{
		if (u == v) return u;
		access(u); access(v);
		if (!u->p) return NULL;
		u->splay(); return u->p ?: u;
	}

	void link(node* u, node* v) // make u parent of v
	{
		assert(!connected(u, v));
		make_root(v);
		access(u); set_link(v, u, 0); v->update();
	}

	void cut(node* u) // cut u from its parent
	{
		access(u);
		u->ch[0]->p = NULL;
		u->ch[0] = NULL;
		u->update();
	}

	void cut(node* u, node* v) // if u, v adj in tree
	{
		cut(depth(u) > depth(v) ? u : v);
	}

	void make_root(node* u) // make u root of LCT component
	{
		access(u);
		u->reverse();
		access(u);
		assert(!u->ch[0] && !u->ch[1]);
	}

	void access(node *u) // puts u on the preferred path, splay (right subtree is empty)
	{
		for (node* v = u, *pre = NULL; v; v = v->p)
		{
			v->splay(); // now update virtual children
			if (pre) v->update_vsub(pre, false);
			if (v->ch[1]) v->update_vsub(v->ch[1], true);
			v->ch[1] = pre; v->update(); pre = v;
		}
		u->splay(); assert(!u->ch[1]);
	}

	node* operator[](int i) { return &data[i]; }
	int operator[](node* i) { return i - &data[0]; }

	vector<node> data;
	link_cut_tree(int n) : data(n) {}
};

template<typename pnode>
struct splay_tree
{
	pnode ch[2], p;

	splay_tree() { ch[0] = ch[1] = p = NULL; }

	int dir()
	{
		if (!p) return -2; // root of LCT component
		if (p->ch[0] == this) return 0; // left child
		if (p->ch[1] == this) return 1; // right child
		return -1; // root of current splay tree
	}

	bool is_root() { return dir() < 0; }

	friend void set_link(pnode u, pnode v, int d)
	{
		if (v) v->p = u;
		if (d >= 0) u->ch[d] = v;
	}

	void rotate() // assume p and p->p propagated
	{
		assert(!is_root());
		int x = dir(); pnode g = p;
		set_link(g->p, static_cast<pnode>(this), g->dir());
		set_link(g, ch[x^1], x);
		set_link(static_cast<pnode>(this), g, x^1);
		g->update(); //update();
	}

	void splay() // bring this to top of splay tree
	{
		const pnode &self = static_cast<pnode>(this);
		while (!is_root() && !p->is_root())
		{
			p->p->push(), p->push(), self->push();
			dir() == p->dir() ? p->rotate() : self->rotate();
			self->rotate();
		}
		if (!is_root()) p->push(), self->push(), self->rotate();
		self->push(); self->update();
	}
};

template<typename pnode, class splay_tree_vchs>
struct splay_tree_lct : splay_tree<pnode>
{
	splay_tree_vchs vnode;

	using splay_tree<pnode>::ch;
	bool rev;
	int sz;

	splay_tree_vchs *root;

	splay_tree_lct() : splay_tree<pnode>() { root = NULL; rev = 0; sz = 1; }

	friend int get_sz(pnode u) { return u ? u->sz : 0; }

	void update()
	{
		sz = 1 + get_sz(ch[0]) + get_sz(ch[1]);
	}

	void push()
	{
	    if (rev)
	    {
	    	if (ch[0]) ch[0]->reverse();
	    	if (ch[1]) ch[1]->reverse();
	    	rev = 0;
	    }
	}

	void rotate()
	{
	    swap(vnode, this->p->vnode);
	    splay_tree<pnode>::rotate();
	}

	void splay()
	{
		auto v = &vnode;
	    bool r = !v->key;
	    splay_tree<pnode>::splay();
	    if (r && v->key)
	    {
	    	if (this->p->root->key == NULL) this->p->root = v;
	    	if (v->p) v->p->ch[v->p->ch[1] == &v->key->vnode] = v;
	    	if (v->ch[0]) v->ch[0]->p = v;
	    	if (v->ch[1]) v->ch[1]->p = v;
	    	v->key = static_cast<pnode>(this);
	    }
	}

	void reverse()
	{
		rev ^= 1;
		swap(ch[0], ch[1]);
	}

	void update_vsub(pnode v, bool add)
	{
		auto &u = root;
		if (add)
		{
			v->vnode = splay_tree_vchs(v);
			if (!u) { u = &v->vnode; return; }
			u->push();
			while (u->ch[1]) u = u->ch[1], u->push();
			u->ch[1] = &v->vnode;
			u->ch[1]->p = u;
			u = u->ch[1];
			u->splay();
		}
		else
		{
			auto x = &v->vnode;
			x->splay();
			if (!x->ch[0]) { u = x->ch[1]; }
			else if (!x->ch[1]) { u = x->ch[0]; }
			else
			{
				u = x->ch[0];
				u->p = NULL;
				u->push();
				while (u->ch[1]) u = u->ch[1], u->push();
				u->ch[1] = x->ch[1];
				x->ch[1]->p = u;
				u->splay();
			}
			if (u) u->p = NULL;
			x->key = NULL;
		}
	}
};

template<typename pnode>
struct splay_tree_vchs : splay_tree<splay_tree_vchs<pnode>*>
{
	using splay_tree<splay_tree_vchs<pnode>*>::ch;
	pnode key;

	int sub;

	splay_tree_vchs() : key(NULL) {};
	splay_tree_vchs(const pnode &key) : splay_tree<splay_tree_vchs<pnode>*>(), key(key) { build(); }

	void build()
	{
		sub = key->sub;
	}

	void update()
	{
		build();
		if (ch[0]) sub = max(sub, ch[0]->sub);
		if (ch[1]) sub = max(sub, ch[1]->sub);
	}

	void push() {}
};

struct node : splay_tree_lct<node*, splay_tree_vchs<node*>>
{
	int x, sub;

	node() : splay_tree_lct() { x = sub = 0; }

	void update()
	{
		splay_tree_lct::update();
		sub = x;
		if (root) sub = max(x, root->sub);
		if (ch[0]) sub = max(sub, ch[0]->sub);
		if (ch[1]) sub = max(sub, ch[1]->sub);
	}

	void push()
	{
		splay_tree_lct::push();
	}

	void reverse()
	{
		splay_tree_lct::reverse();
	}
};

int main()
{
	#ifdef TurnRed
		//freopen("a.in", "r", stdin);
		//freopen("a.out", "w", stdout);
	#endif

	ios_base::sync_with_stdio(0), cin.tie(0);

	int n, m, q;
	cin >> n >> m >> q;
	vector<int> p(n), who(n+1);
	link_cut_tree<node> lct(n);
	for (auto &i : p)
	{
		int u = &i-&p[0];
		cin >> i;
		who[i] = u;
		lct[u]->x = lct[u]->sub = i;
	}

	vector<pair<int, int>> edges(m);
	for (auto &i : edges)
		cin >> i.F >> i.S, --i.F, --i.S;

	vector<pair<int, int>> prio(m);
	for (int i = 0; i < m; ++i) prio[i] = { q+1, i };

	vector<pair<int, int>> queries(q);
	for (auto &i : queries)
	{
		cin >> i.F >> i.S, --i.S;
		if (i.F == 2) prio[i.S].F = &i-&queries[0];
	}

	vector<bool> alive(m);
	sort(prio.rbegin(), prio.rend());
	for (auto i : prio)
	{
		int u, v;
		tie(u, v) = edges[i.S];
		if (!lct.connected(lct[u], lct[v]))
		{
			alive[i.S] = true;
			lct.link(lct[u], lct[v]);
		}
	}

	for (auto que : queries)
	{
		if (que.F == 1)
		{
			auto u = lct[que.S];
			lct.access(u);
			cout << u->sub << "\n";
			if (u->sub != 0)
			{
				auto v = lct[who[u->sub]];
				lct.access(v);
				v->x = 0;
				v->update();
			}
		}
		else if (alive[que.S])
		{
			int u, v;
			tie(u, v) = edges[que.S];
			lct.cut(lct[u], lct[v]);
		}
	}

	return 0;
}

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <vector>

#define rep(i,l,r) for (i=l;i<=r;i++)
#define drep(i,l,r) for (i=l;i>=r;i--)
using namespace std;

const int N = 210000, M = 310000, Q = 510000;

int i,j,k,l,m,n,q,o,tot,p[N],a[M],b[M],is_alive[M],cmd[Q],key[Q];
int belong[N],visit[N], e[M*2], sta[N], nex[M*2], lastq;

inline int getint()
{
	int o = 0; char c = getchar();
	while (c>='0' && c<='9'){o = (o<<1) + (o<<3) + c - '0'; c = getchar();}
	return o;
}
struct arr
{
	int i, p;
	arr(){}
	arr(int I, int P) {i = I; p = P;}
	inline bool operator < (const arr & _) const
	{
		return (p > _.p) || (p == _.p && i < _.i);
	}
}f[N];
set<arr> F[N];

inline void init()
{
	n = getint(); m = getint(); q = getint();
	rep(i,1,n)
	{
		// scanf("%d",&p[i]);
		p[i] = getint();
		f[i] = arr(i,1);
		belong[i] = 0; visit[i] = 0; sta[i] = 0;
	}
	l = 1;
	rep(i,1,m)
	{
		// scanf("%d%d",&a[i],&b[i]);
		a[i] = getint(); b[i] = getint();
		is_alive[i] = 1;
		nex[++l] = sta[a[i]]; sta[a[i]] = l; e[l] = b[i];
		nex[++l] = sta[b[i]]; sta[b[i]] = l; e[l] = a[i];
	}
	rep(i,1,q)
	{
		// scanf("%d%d",&cmd[i],&key[i]);
		cmd[i] = getint(); key[i] = getint();
		if (cmd[i] == 2) is_alive[key[i]] = 0; else lastq=i;
	}
}

inline int getf(int x)
{
	if (f[x].i == x) return x;
	return f[x].i = getf(f[x].i);
}

inline void solve_back()
{
	int i, u, v;
	rep(i,1,m) if (is_alive[i])
	{
		u = getf(a[i]); v = getf(b[i]);
		f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
	}
	drep(i,q,1) if (cmd[i] == 2)
	{
		u = getf(a[key[i]]); v = getf(b[key[i]]);
		if (u == v) {a[key[i]] = b[key[i]] = 0;} else
		{
			if (f[u].p > f[v].p)
			{
				swap(a[key[i]], b[key[i]]); swap(u,v);
			}
			f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
		}
	}
}

inline void dfs(int x, int t)
{
	if (p[x]) {F[belong[x]].erase(arr(x,p[x])); F[t].insert(arr(x,p[x])); }
	belong[x] = t;
	for (int j = sta[x]; j; j = nex[j]) if (is_alive[j>>1] && visit[e[j]]!=t)
	{
		visit[e[j]] = t; dfs(e[j], t);
	}
}
inline void solve()
{
	int i, u, v, j, t, ans;
	set <arr> :: iterator pos;
	rep(i,1,m) is_alive[i] = 1;
	tot = 0;
	rep(i,1,n) if (visit[i] == 0)
	{
		++tot; F[tot].clear();
		dfs(i,tot);
	}
	rep(i,1,lastq)
	{
		// if (i > 100000){printf("FUCK%d\n",i); break;}
		if (cmd[i] == 1)
		{
			v = key[i]; t = belong[v]; ans = 0;
			if (F[t].size())
			{
				pos = F[t].begin();
				u = (*pos).i; ans = (*pos).p;
				F[t].erase(pos); p[u] = 0;
			}
			printf("%d\n",ans);
		}
		if (cmd[i] == 2)
		{
			u = a[key[i]]; v = b[key[i]];  is_alive[key[i]] = 0;
			if (u > 0 && v > 0)
			{
				++tot; F[tot].clear();
				dfs(u,tot);
			}
		}
	}
}
int main()
{
	// freopen("1.in","r",stdin); freopen("1.out","w",stdout);
	init();
	solve_back();
	solve();
	// fclose(stdin); fclose(stdout);
	return 0;
}

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5;
#define ls now<<1
#define rs now<<1|1
#define F first
#define S second
int Head[N],vet[N<<1],Next[N<<1];
int E[N][2],que[N<<2][3],bl[N],sz[N],FA[N],p[N],tree[N<<2],loc[N<<2],vis[N],val[N],fa[N][20];
pair<int,int> ran[N];
vector<int> vec[N];
int n,m,q,edgenum,nodenum,ans,LOC,cnt,now;
int find(int u){ return FA[u]==u?u:FA[u]=find(FA[u]); }
inline void addedge(int u, int v){
	edgenum++;
	vet[edgenum]=v;
	Next[edgenum]=Head[u];
	Head[u]=edgenum;
}
void update(int now, int l, int r, int x, int y){
	if (l==r){ tree[now]=y; loc[now]=x; return; }
	int mid=(l+r)>>1;
	if (mid>=x) update(ls,l,mid,x,y);
	else update(rs,mid+1,r,x,y);
	tree[now]=max(tree[ls],tree[rs]);
	if (tree[ls]>tree[rs]) loc[now]=loc[ls];
	else loc[now]=loc[rs];
}
void query(int now, int l, int r, int x, int y){
	if (l==x && r==y){
		if (tree[now]>=ans) ans=tree[now],LOC=loc[now];
		return;
	}
	int mid=(l+r)>>1;
	if (mid>=y) query(ls,l,mid,x,y);
	else if (mid<x) query(rs,mid+1,r,x,y);
	else query(ls,l,mid,x,mid),query(rs,mid+1,r,mid+1,y);
}
void dfs(int u){
	vis[u]=1; bl[u]=cnt; sz[cnt]++;
	vec[cnt].push_back(u);
	for (int e=Head[u]; e; e=Next[e]){
		int v=vet[e];
		if (!vis[v]) dfs(v);
	}
}
void dfs1(int u, int f){
	fa[u][0]=f; ran[u]=make_pair(1e9,0);
	for (int i=1; i<=19; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
	if (val[u]==-1){
		ran[u]=make_pair(now+1,now+sz[u]);
		for (int i=0; i<sz[u]; i++) update(1,1,n,now+i+1,p[vec[u][i]]);
		now+=sz[u]; return;
	}
	for (int e=Head[u]; e; e=Next[e]){
		int v=vet[e];
		dfs1(v,u);
		ran[u].F=min(ran[u].F,ran[v].F);
		ran[u].S=max(ran[u].S,ran[v].S);
	}
}
inline int read(){
	int num=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9') num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
	return num;
}
void print(int x){
	if (!x) return;
	print(x/10); putchar(x%10+'0');
}
int main(){
//	freopen("D.in","r",stdin);
//	freopen("D.out","w",stdout);
	n=read(),m=read(),q=read();
	for (int i=1; i<=n; i++) p[i]=read();
	for (int i=1; i<=m; i++) E[i][0]=read(),E[i][1]=read();
	for (int i=1; i<=q; i++){
		que[i][0]=read(),que[i][1]=read();
		if (que[i][0]==2) vis[que[i][1]]=1,que[i][2]=i;
	}
	for (int i=1; i<=m; i++)
		if (!vis[i]) addedge(E[i][0],E[i][1]),addedge(E[i][1],E[i][0]);
	memset(vis,0,sizeof(vis));
	for (int i=1; i<=n; i++)
		if (!vis[i]) cnt++,dfs(i),FA[cnt]=cnt,val[cnt]=-1;
	memset(Head,0,sizeof(Head)); edgenum=0; nodenum=cnt;
	for (int i=q; i>=1; i--){
		if (que[i][0]==1) continue;
		int u=bl[E[que[i][1]][0]],v=bl[E[que[i][1]][1]];
		u=find(u),v=find(v);
		if (u!=v){
			nodenum++; val[nodenum]=que[i][2];
			FA[nodenum]=FA[u]=FA[v]=nodenum;
			addedge(nodenum,u); addedge(nodenum,v);
		}
	}
	for (int i=nodenum; i>=1; i--)
		if (ran[i]==make_pair(0,0)) dfs1(i,0);
	for (int i=1; i<=q; i++){
		if (que[i][0]==2) continue;
		int u=bl[que[i][1]];
		for (int j=19; ~j; j--)
			if (val[fa[u][j]]>i) u=fa[u][j];
		ans=LOC=-1; query(1,1,n,ran[u].F,ran[u].S);
		if (!ans) puts("0");
		else print(ans),puts("");
		update(1,1,n,LOC,0);
	}
	return 0;
}
/*
5 4 6
1 2 5 4 3
1 2
2 3
1 3
4 5
1 1
2 1
2 3
1 1
1 2
1 2
*/

// Mivik 2020.9.29
#include <iostream>
#include <cstring>
#include <cstdio>

#define d isdigit(c)
#define g c=t.get();
#define L return
#define K break
#define A(c,a,b)if(c)a else b;
#define I(c,a)if(c)a;
#define Y goto E
struct MI{private:char bb[4096];FILE*f;char*bs,*be;char e;bool o,l;public:MI():f(stdin){}
#ifdef __linux__
#endif
inline char get(){if(o){o=0;L e;}
#ifdef MIVIK
char c=fgetc(f);I(c==-1,l=1)L c;
#else
I(bs==be,be=(bs=bb)+fread(bb,1,sizeof(bb),f))I(bs==be,{l=1;L-1;})L*bs++;
#endif
}inline void unget(char c){o=1;e=c;}template<typename T>inline T read(){T r;*this>r;L r;}template<typename T>inline MI&operator>(T&);};template<typename T>struct Q{const static bool U=T(-1)>=T(0);inline void operator()(MI&t,T&r)const{r=0;char c;bool y=0;A(U,for(;;){g I(c==-1,Y)I(d,K)},for(;;){g I(c==-1,Y)A(c=='-',{g I(d,{y=1;K;})},I(d,K))})for(;;){I(c==-1,Y)A(d,r=r*10+(c^48);,K)g}t.unget(c);E:;I(y,r=-r)}};template<>struct Q<char>{};template<typename T>inline MI&MI::operator>(T&t){Q<T>()(*this,t);L*this;}
#undef d
#undef g
#undef L
#undef K
#undef A
#undef I
#undef Y
template<typename T>std::ostream& operator<(std::ostream&out,const T&t){return out<<t;}
#define endl ('\n')
#define P(x) cout < #x" = " < (x) < endl
#define R (cin.read<int>())

using std::cout;

#include <climits>

using std::make_pair;
using std::pair;

#ifdef MIVIK
MI cin(popen("xsel -ob", "r"));
#else
MI cin;
#endif

const int nmax = 200001;
const int pmax = nmax * 2;
const int qmax = 500005;
const int tmax = 1048577;

template<typename T> inline bool getmax(T &a, const T &b) { return a < b && (a = b, true); }

int n, m, q;
int a[nmax];
int fro[qmax], tar[qmax];
bool del[qmax];
pair<bool, int> qs[qmax];
int tot;
int f[pmax], ls[pmax], rs[pmax], rin[pmax], ind[pmax], rig[pmax], val[pmax];

namespace seg {
#define ls (x << 1)
#define rs (ls | 1)
#define G const int mid = (l + r) >> 1
#define LL ls, l, mid
#define RR rs, mid + 1, r

int mx[tmax], ll, rr, vv, tx, tl, tr;
inline void pu(int x) { mx[x] = std::max(mx[ls], mx[rs]); }
void _build(int x, int l, int r) {
	if (l == r) return (void)(mx[x] = val[l]);
	G;
	_build(LL);
	_build(RR);
	pu(x);
}
inline void build() { _build(1, 1, tot); }
void _clear(int x, int l, int r) {
	if (l == r) return (void)(mx[x] = 0);
	G;
	(mx[ls] == mx[x]) ? _clear(LL) : _clear(RR);
	pu(x);
}
void _query(int x, int l, int r) {
	if (ll <= l && r <= rr) {
		if (getmax(vv, mx[x])) {
			tx = x;
			tl = l;
			tr = r;
		}
		return;
	}
	G;
	if (ll <= mid) _query(LL);
	if (mid < rr) _query(RR);
}
inline int query(int l, int r) {
	ll = l;
	rr = r;
	vv = 0;
	_query(1, 1, tot);
	if (vv) _clear(tx, tl, tr);
	return vv;
}

#undef ls
#undef rs
#undef G
#undef LL
#undef RR
} // namespace seg

int getf(int x) { return (x == f[x]) ? x : (f[x] = getf(f[x])); }
inline void merge(int x, int y) {
	x = getf(x);
	y = getf(y);
	if (x == y) return;
	const int t = ++tot;
	f[x] = f[y] = f[t] = t;
	ls[t] = x;
	rs[t] = y;
}
void dfs(int x) {
	static int tot;
	if (!x) return;
	ind[x] = ++tot;
	val[tot] = (x <= n) ? a[x] : INT_MIN;
	dfs(ls[x]);
	dfs(rs[x]);
	rig[x] = tot;
}
int main() {
	cin > n > m > q;
	for (int i = 1; i <= n; ++i) {
		cin > a[i];
		f[i] = i;
	}
	for (int i = 1; i <= m; ++i) cin > fro[i] > tar[i];
	for (int i = 1; i <= q; ++i) {
		const int op = R;
		qs[i] = make_pair(op == 2, R);
		if (op == 2) del[qs[i].second] = 1;
	}
	tot = n;
	for (int i = 1; i <= m; ++i)
		if (!del[i]) merge(fro[i], tar[i]);
	for (int i = q; i; --i) {
		auto &pa = qs[i];
		if (pa.first)
			merge(fro[pa.second], tar[pa.second]);
		else
			pa.second = getf(pa.second);
	}
	for (int i = 1; i <= tot; ++i)
		if (getf(i) == i) dfs(i);
	seg::build();
	for (int i = 1; i <= q; ++i) {
		const auto &pa = qs[i];
		if (pa.first) continue;
		cout < seg::query(ind[pa.second], rig[pa.second]) < endl;
	}
	return 0;
}

#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
#include <set>

using namespace std;

#define f first
#define s second

const int MAXN = 5e5 + 3;

int w[MAXN];
bool us[MAXN];
bool was[MAXN];
bool nal[MAXN];
int repr[MAXN];
int nas[MAXN];
int lst[MAXN];
int roz[MAXN];
int who[MAXN];
multiset<int> q[MAXN];
pair<int, int> pol[MAXN];
pair<int, int> zap[MAXN];

int fnd(int x) {
    if (repr[x] == x)
        return x;
    return repr[x] = fnd(repr[x]);
}

void onion(int x, int y, int ind, int ind2) {
    x = fnd(x);
    y = fnd(y);
    if (x == y)
        return;
    if (roz[x] < roz[y]) {
        swap(pol[ind].f, pol[ind].s);
        swap(x, y);
    }
    nal[ind2] = true;
    who[ind2] = y;
    repr[y] = x;
    nas[lst[x]] = y;
    lst[x] = lst[y];
    roz[x] += roz[y];
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m, z;
    int x, y, war, pocz, sec;
    cin >> n >> m >> z;
    for (int i = 1; i <= n; i++) {
        cin >> w[i];
        w[i] *= -1;
    }
    for (int i = 1; i <= m; i++)
        cin >> pol[i].f >> pol[i].s;
    for (int i = 1; i <= z; i++) {
        cin >> zap[i].f >> zap[i].s;
        if (zap[i].f == 2)
            us[zap[i].s] = true;
    }
    for (int i = 1; i <= n; i++) {
        repr[i] = nas[i] = lst[i] = i;
        roz[i] = 1;
    }
    for (int i = 1; i <= m; i++) {
        if (!us[i])
            onion(pol[i].f, pol[i].s, i, 0);
    }
    for (int i = z; i > 0; i--) {
        if (zap[i].f == 2)
            onion(pol[zap[i].s].f, pol[zap[i].s].s, zap[i].s, i);
    }
    for (int i = 1; i <= n; i++)
        q[fnd(i)].insert(w[i]);

    for (int i = 1; i <= z; i++) {
        if (zap[i].f == 1) {

            x = fnd(zap[i].s);
            war = -(*q[x].begin());
            cout << war << '\n';
            q[x].erase(q[x].begin());
            q[x].insert(0);

            was[war] = true;
        }
        else if (nal[i]) {

            x = pol[zap[i].s].f;
            x = fnd(x);
            pocz = y = who[i];
            sec = lst[y];

            while (true) {
                repr[y] = pocz;
                if (!was[-w[y]]) {
                    q[pocz].insert(w[y]);
                    q[x].erase(q[x].find(w[y]));
                }
                else
                    q[pocz].insert(0);
                if (y == sec)
                    break;
                y = nas[y];
            }

            continue;
        }
    }
    return 0;
}

#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define rc(x) return cout<<x<<endl,0
#define pb push_back
#define mkp make_pair
#define in insert
#define er erase
#define fd find
#define fr first
#define sc second
#define all(x) x.begin(),x.end()
#define lun(x) (int)x.size()
typedef long long ll;
typedef long double ld;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll llinf=(1LL<<60);
const int inf=(1<<30);
const int nmax=5e5+50;
const ll mod=1e9+7;
using namespace std;
int n,m,q,i,sz,tt,x,y,ex[nmax],ey[nmax],vl[nmax],v[nmax],p[nmax],in[nmax],out[nmax],tp[nmax],gl[nmax],er[nmax],viz[nmax],nd[nmax];
vector<int>a[nmax];
pair<int,int>st[4*nmax],pr;
int fnd(int x)
{
    if(p[x]==x)return x;
    return p[x]=fnd(p[x]);
}
void uni(int x,int y)
{
    x=fnd(x),y=fnd(y);
    if(x==y)return;
    sz++;
    p[x]=sz;
    p[y]=sz;
    p[sz]=sz;
    a[sz].pb(x);
    a[sz].pb(y);
}
void dfs(int x)
{
    viz[x]=1;
    in[x]=++tt;
    nd[tt]=x;
    for(int i=0;i<lun(a[x]);i++)if(!viz[a[x][i]])dfs(a[x][i]);
    out[x]=tt;
}
void build(int nod,int l,int r)
{
	if(l==r)
	{
		st[nod]=mkp(v[nd[l]],l);
		return;
	}
	int mid=(l+r)/2;
	build(2*nod,l,mid);
	build(2*nod+1,mid+1,r);
	st[nod]=max(st[2*nod],st[2*nod+1]);
}
void upd(int nod,int l,int r,int p)
{
	if(l==r)
	{
		st[nod]=mkp(0,0);
		return;
	}
	int mid=(l+r)/2;
	if(p<=mid)upd(2*nod,l,mid,p);
	else upd(2*nod+1,mid+1,r,p);
	st[nod]=max(st[2*nod],st[2*nod+1]);
}
pair<int,int> qry(int nod,int l,int r,int tl,int tr)
{
	if(tr<l || tl>r)return mkp(0,0);
	if(tl<=l && r<=tr)return st[nod];
	int mid=(l+r)/2;
	return max(qry(2*nod,l,mid,tl,tr),qry(2*nod+1,mid+1,r,tl,tr));
}
int main()
{
	//freopen("sol.in","r",stdin);
	//freopen("sol.out","w",stdout);
	//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
	ios_base::sync_with_stdio(false);cin.tie(0);cerr.tie(0);cout.tie(0);
    cin>>n>>m>>q;
    for(i=1;i<=n;i++)cin>>v[i];
    for(i=1;i<=m;i++)cin>>ex[i]>>ey[i];
    for(i=1;i<=n;i++)p[i]=i;
    sz=n;
    for(i=1;i<=q;i++)
    {
        cin>>tp[i]>>vl[i];
        if(tp[i]==2)er[vl[i]]=1;
    }
    for(i=1;i<=m;i++)
    {
        if(er[i])continue;
        x=ex[i],y=ey[i];
        uni(x,y);
    }
    for(i=q;i>=1;i--)
    {
        if(tp[i]==1)gl[i]=fnd(vl[i]);
        else uni(ex[vl[i]],ey[vl[i]]);
    }
    for(i=sz;i>=1;i--)
    {
        if(viz[i])continue;
        dfs(i);
    }
    build(1,1,tt);
    for(i=1;i<=q;i++)
    {
        if(tp[i]==2)continue;
        x=gl[i];
        pr=qry(1,1,tt,in[x],out[x]);
        upd(1,1,tt,pr.sc);
        cout<<pr.fr<<'\n';
    }
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define M 500005
typedef pair<vector<int>, int> pvi;

int pp[M];
int uu[M], vv[M];
int tp[M], id[M];
bool ase[M];
int boss[M];
vector<int> vec[M];
pvi cng[M];

void mf(int a, int b)
{
    int u = boss[a], v = boss[b];
    if(u == v) return;

    if(vec[u].size() > vec[v].size()) swap(u, v);

    for(int x: vec[u])
    {
        boss[x] = v;
        vec[v].push_back(x);
    }
}

bool cmp(int a, int b) { return pp[a] < pp[b]; }

int main()
{
    int n, m, q;
    scanf("%d %d %d", &n, &m, &q);

    for(int i = 1; i <= n; i++) scanf("%d", pp+i);
    for(int i = 1; i <= m; i++) scanf("%d %d", uu+i, vv+i);
    for(int i = 1; i <= q; i++) scanf("%d %d", tp+i, id+i);

    for(int i = 1; i <= q; i++)
    {
        if(tp[i] == 2) ase[id[i]] = true;
    }

    for(int i = 1; i <= n; i++) boss[i] = i, vec[i].push_back(i);
    for(int i = 1; i <= m; i++)
    {
        if(!ase[i]) mf(uu[i], vv[i]);
    }

    for(int i = q; i; i--)
    {
        if(tp[i] == 1) continue;
        int u = boss[uu[id[i]]], v = boss[vv[id[i]]];
        if(u == v) continue;
        if(vec[u].size() > vec[v].size()) swap(u, v);

        cng[i] = {vec[u], u};
        mf(uu[id[i]], vv[id[i]]);
    }

    for(int i = 1; i <= n; i++) sort(vec[i].begin(), vec[i].end(), cmp);

    for(int i = 1; i <= q; i++)
    {
        if(tp[i] == 1)
        {
            int u = boss[id[i]];
            while(vec[u].size() && (boss[vec[u].back()] != u || !pp[vec[u].back()])) vec[u].pop_back();

            int ans = 0;
            if(vec[u].size()) ans = pp[vec[u].back()], pp[vec[u].back()] = 0;

            printf("%d\n", ans);
        }
        else
        {
            for(int x: cng[i].first) boss[x] = cng[i].second;
        }
    }

    return 0;
}

/*
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⢀⡀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡖⠁⠀⠀⠀⠀⠀⠀⠈⢲⣄
⠀⠀⠀⠀⠀⠀⠀⠀⣼⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣧
⠀⠀⠀⠀⠀⠀⠀⣸⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣇
⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀⢀⣀⣤⣤⣤⣤⣀⡀⠀⢸⣿⣿
⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣔⢿⡿⠟⠛⠛⠻⢿⡿⣢⣿⣿⡟
⠀⠀⠀⠀⣀⣤⣶⣾⣿⣿⣿⣷⣤⣀⡀⢀⣀⣤⣾⣿⣿⣿⣷⣶⣤⡀
⠀⠀⢠⣾⣿⡿⠿⠿⠿⣿⣿⣿⣿⡿⠏⠻⢿⣿⣿⣿⣿⠿⠿⠿⢿⣿⣷⡀
⠀⢠⡿⠋⠁⠀⠀⢸⣿⡇⠉⠻⣿⠇⠀⠀⠸⣿⡿⠋⢰⣿⡇⠀⠀⠈⠙⢿⡄
⠀⡿⠁⠀⠀⠀⠀⠘⣿⣷⡀⠀⠰⣿⣶⣶⣿⡎⠀⢀⣾⣿⠇⠀⠀⠀⠀⠈⢿
⠀⡇⠀⠀⠀⠀⠀⠀⠹⣿⣷⣄⠀⣿⣿⣿⣿⠀⣠⣾⣿⠏⠀⠀⠀⠀⠀⠀⢸
⠀⠁⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⢇⣿⣿⣿⣿⡸⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠈
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⣿⣿⣿⣿⣧⡀
⠀⠀⠀⠐⢤⣀⣀⢀⣀⣠⣴⣿⣿⠿⠋⠙⠿⣿⣿⣦⣄⣀⠀⠀⣀⡠⠂
⠀⠀⠀⠀⠀⠈⠉⠛⠛⠛⠛⠉⠀⠀⠀⠀⠀⠈⠉⠛⠛⠛⠛⠋⠁
              vsriram1012
*/
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ii pair<int,int>
#define ll long long
// #define uint128 __uint128_t
// #define int128 __int128
#define pll pair<ll,ll>
// order_of_key(k), find_by_order(k)
#define ordered_set \
    tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define iiordered_set \
    tree<pll, null_type,less<pll>, rb_tree_tag,tree_order_statistics_node_update>
using namespace std;
auto clk=clock();
mt19937_64 rang(chrono::high_resolution_clock::now().time_since_epoch().count());
ll rng(ll lim) {
    uniform_int_distribution<ll> uid(0,lim-1);
    return uid(rang);
}
#define rd(x)   scanf("%d",&x);
#define numSetBits(x) __builtin_popcountll(x)
#define MOD 1000000007
// #define MOD 998244353
#define left(x) (x<<1)
#define right(x)    ((x<<1)|1)
// #define mid(l,r)    ((l+r)>>1)
const ll INFl=1e18;
#define vi vector<int>
#define vvi vector<vi>
#define vl vector<long long>
#define vvl vector<vl>
#define forl(i,n) for(int i=0;i<n;i++)
#define fore(i,n) for(int i=1;i<=n;i++)
#define debug(x)    cout<<"DEBUG: "<<x<<endl;
ll power(ll a,ll b, ll m=MOD)
{
    ll res=1;
    while(b>0)
    {
        if(b&1)
            res=(res*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
    return res;
}
ll inverse(ll a,ll m=MOD)
{
    return power(a,m-2,m);
}
int ceil(int a,int b)
{
    return (a+b-1)/b;
}
#define sz(x) (x.size())
#define vll vector<pll>
#define vii vector<ii>
#define vvii vector<vii>
#define F first
#define S second
#define forl(i,n) for(int i=0;i<n;i++)
#define fore(i,n) for(int i=1;i<=n;i++)
#define CASE(t) cout<<"Case #"<<(t)<<": ";
#define INF 1020000000
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) ((a)*(b)/gcd(a,b))
#define all(x)  x.begin(),x.end()
#define mp make_pair
#define pb push_back
#define print(x)    \
    for(auto it=x.begin();it!=x.end();it++) cout<<*it<<' '; cout<<endl;
#define print2d(x)  \
    for(auto it1=x.begin();it1!=x.end();it1++) {print((*it1));}
#define printii(x)  \
        for(auto it=x.begin();it!=x.end();it++) cout<<it->F<<' '<<it->S<<endl;
vvl matmul(const vvl &a,const vvl &b,ll M=MOD)
{
    int n=a.size(),m=a[0].size(),l=b[0].size();
    assert(m==b.size());
    vvl c(n,vl(l,0));
    forl(i,n)forl(j,l)forl(k,m)
    {
        c[i][j]=(c[i][j]+a[i][k]*b[k][j])%M;
    }
    return c;
}
vvl matpow(vvl a,ll p,ll M=MOD)
{
    assert(a.size()==a[0].size());
    int n=a.size();
    vvl res(n,vl(n,0));
    forl(i,n)   res[i][i]=1;
    while(p>0)
    {
        if(p&1) res=matmul(res,a,M);
        a=matmul(a,a,M);
        p>>=1;
    }
    return res;
}
void sieve(vi& primes,int mx)
{
    vi is_comp(mx,0);
    for(int i=2;i<mx;i++)
    {
        if(!is_comp[i])
            primes.pb(i);
        for(int j=0;j<primes.size()&&primes[j]*i<mx;j++)
        {
            is_comp[i*primes[j]]=1;
            if(i%primes[j]==0)
                break;
        }
    }
}
int euc(int a,int b,int &x,int &y){
    if(!b){x=1;y=0;return a;}
    int x1,y1,g=euc(b,a%b,x1,y1);
    x=y1;y=x1-a/b*y1;
    return g;
}
int crt(int a,int n,int b,int m){
    int dif=b-a,x,y,g=euc(n,m,x,y),l=lcm(n,m);
    if(dif%g)   return -1;
    int res=(((x*dif/g)%(m/g))*n%l+a)%l;
    if(res<0)   res+=l;
    return res;
}
#define fastio ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL)
void solve();
void init();
signed main()
{
    // #ifndef loc
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // #endif
    fastio;
    init();
    signed T=1;
    // cin>>T;
    fore(t,T)
    {
        // CASE(t);
        solve();
    }

#ifdef loc
        cout<<"~~~~~~~~~~~~~~~~~~~~~~~~"<<endl<<"Time elapsed: "
        <<(double)(clock()-clk)/CLOCKS_PER_SEC<<endl;
#endif
}

void init()
{

}
vii split;
struct UnionFind
{
    int n;
    vi p;
    vvi x;
    UnionFind(int N)
    {
        n=N;
        p.assign(N,0);
        x.resize(N);
        for(int i=0;i<N;i++)
            p[i]=i,x[i].pb(i);
    }
    int FindSet(int i)
    {
        return (p[i]==i)?i:(p[i]=FindSet(p[i]));
    }
    bool isSameSet(int i,int j)
    {
        return FindSet(i)==FindSet(j);
    }
    void UnionSet(int i,int j,int idx)
    {
        int p1=FindSet(i);
        int p2=FindSet(j);
        if(p1!=p2)
        {
            if(sz(x[p1])>=sz(x[p2])){
                p[p2]=p1;
                for(int t:x[p2]){
                    x[p1].pb(t);
                }
                split[idx]=mp(p1,p2);
            }
            else{
                p[p1]=p2;
                for(int t:x[p1]){
                    x[p2].pb(t);
                }
                split[idx]=mp(p2,p1);
            }
        }
    }
    void disp()
    {
        for(int i=0;i<n;i++)
            cout<<p[i]<<' ';
        cout<<endl;
    }
};
void solve()
{
    int n,m,q;
    cin>>n>>m>>q;
    vi p(n);
    forl(i,n)   cin>>p[i];
    UnionFind uf(n);
    vii edges(m);
    split.assign(q+5,mp(-1,-1));
    vector<bool> avail(m,true);
    forl(i,m){
        int u,v;
        cin>>u>>v;u--;v--;
        edges[i]=mp(u,v);
    }
    // printii(edges);
    vii queries(q+5);
    forl(i,q){
        int t,x;
        cin>>t>>x;x--;
        queries[i]=mp(t,x);
        if(t==2)    avail[x]=false;
    }
    forl(i,m){
        if(avail[i]){
            uf.UnionSet(edges[i].F,edges[i].S,q);
        }
    }
    for(int i=q-1;i>=0;i--){
        int t,x;
        t=queries[i].F,x=queries[i].S;
        if(t==1) split[i].F=uf.FindSet(x);
        else uf.UnionSet(edges[x].F,edges[x].S,i);
    }
    vector<multiset<int>> val(n);
    forl(i,n){
        if(uf.p[i]==i){
            vi &tmp=uf.x[i];
            for(int x:tmp){
                val[i].insert(p[x]);
            }
        }
    }
    forl(i,q){
        int t,x;
        t=queries[i].F,x=queries[i].S;
        if(t==1){
            int id=split[i].F;
            if(val[id].empty()) cout<<0<<endl;
            else{
                int mx=*val[id].rbegin();
                cout<<mx<<endl;
                val[id].erase(val[id].find(mx));
            }
        }
        else{
            int p1=split[i].F,p2=split[i].S;
            if(p1==-1)  continue;
            vi &tmp=uf.x[p2];
            for(int v:tmp){
                if(val[p1].count(p[v])){
                    val[p1].erase(p[v]);
                    val[p2].insert(p[v]);
                }
            }
        }
    }
}

#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

typedef double db;
typedef long long ll;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;

typedef pair < db, db > pdd;
typedef pair < db, ld > pdl;
typedef pair < ld, db > pld;
typedef pair < ld, ld > ldp;

typedef pair < ll, ll > pll;
typedef pair < int, ll > pil;
typedef pair < ll, int > pli;
typedef pair < int, int > pii;

#define F first
#define S second

#define en end()
#define bg begin()

#define rev reverse
#define mp make_pair
#define pb push_back

#define y1 y1234567890
#define um unordered_map

#define all(x) x.bg, x.en
#define sz(x) (int)x.size()
#define len(x) (int)strlen(x)

#define sqr(x) ((x + 0ll) * (x))
#define sqrd(x) ((x + 0.0) * (x))

#define forn(i, n) for (int i = 1; i <= n; i++)

const int inf = (int)1e9;
const ll mod = (ll)1e9 + 7;

const db eps = (db)1e-9;
const db pi = acos(-1.0);

const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

const int N = 1000500;

pii t[N << 2];
bool er[N], u[N];
vector < int > g[N];
int timer, eu[N], tin[N], tout[N];
int n, m, q, a[N], e[N][2], tp[N], qr[N], ver[N], p[N];

int get(int v) {
	return (v == p[v] ? v : p[v] = get(p[v]));
}

void dfs(int v) {
	u[v] = 1;
	if (g[v].empty()) {
		eu[++timer] = v;
		tin[v] = tout[v] = timer;
		return;
	}
	tin[v] = inf;
	for (auto to : g[v]) {
		if (!u[to])
			dfs(to);
		tin[v] = min(tin[v], tin[to]);
		tout[v] = max(tout[v], tout[to]);
	}
}

void build(int v, int l, int r) {
	if (l == r) {
		t[v] = {a[eu[r]], r};
		return;
	}
	int mid = (l + r) >> 1;
	build(v << 1, l, mid);
	build(v << 1 | 1, mid + 1, r);
	t[v] = max(t[v << 1], t[v << 1 | 1]);
}

void upd(int v, int l, int r, int pos) {
	if (l == r) {
		t[v] = {0, r};
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid)
		upd(v << 1, l, mid, pos);
	else
		upd(v << 1 | 1, mid + 1, r, pos);
	t[v] = max(t[v << 1], t[v << 1 | 1]);
}

pii get(int v, int l, int r, int lx, int rx) {
	if (rx < l || r < lx)
		return {0, 0};
	if (lx <= l && r <= rx)
		return t[v];
	int mid = (l + r) >> 1;
	return max(get(v << 1, l, mid, lx, rx), get(v << 1 | 1, mid + 1, r, lx, rx));
}

int main() {
	//freopen(".in", "r", stdin);
	//freopen(".out", "w", stdout);
	//freopen(".err", "w", stderr);

	//mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());

	//cin.tie(NULL);
	//cout.tie(NULL);
	//ios_base::sync_with_stdio(false);

	//cout << setprecision(10) << fixed;

	scanf("%d %d %d", &n, &m, &q);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		p[i] = i;
	}
	for (int i = 1; i <= m; i++)
		scanf("%d %d", &e[i][0], &e[i][1]);
	for (int i = 1; i <= q; i++) {
		scanf("%d %d", &tp[i], &qr[i]);
		if (tp[i] == 2)
			er[qr[i]] = 1;
	}

	for (int i = 1; i <= m; i++) {
		if (!er[i]) {
			q++;
			tp[q] = 2;
			qr[q] = i;
		}
	}

	int ptr = n;

	for (int i = q; i >= 1; i--) {
		if (tp[i] == 1)
			ver[i] = get(qr[i]);
		else {
			int x = get(e[qr[i]][0]);
			int y = get(e[qr[i]][1]);
			if (x != y) {
				++ptr;
				p[x] = p[y] = p[ptr] = ptr;
				g[ptr].pb(x);
				g[ptr].pb(y);
			}
		}
	}

	for (int i = ptr; i >= 1; i--) {
		if (!u[i])
			dfs(i);
	}
	build(1, 1, n);

	for (int i = 1; i <= q; i++) {
		if (tp[i] == 2) continue;
		pii res = get(1, 1, n, tin[ver[i]], tout[ver[i]]);
		printf("%d\n", res.F);
		upd(1, 1, n, res.S);
	}

	//cerr << (clock() + 0.0) / CLOCKS_PER_SEC;

	return 0;
}

#include<bits/stdc++.h>

using namespace std;

#define  GODSPEED       ios:: sync_with_stdio(0);cin.tie(0);cout.tie(0);cout<<fixed;cout<<setprecision(15);
#define  f              first
#define  s              second
#define  newl           cout<<"\n";
#define  pb             push_back
#define  mset(a,x)      memset(a,x,sizeof(a))
#define  debv(a)        for(auto it: a)cout<<it<<" ";newl;
#define  deb1(a)        cout<<a<<"\n";
#define  deb2(a,b)      cout<<a<<" "<<b<<"\n";
#define  deb3(a,b,c)    cout<<a<<" "<<b<<" "<<c<<"\n";
#define  deb4(a,b,c,d)  cout<<a<<" "<<b<<" "<<c<<" "<<d<<"\n";
#define  uniq(a)        a.resize(unique(a.begin(), a.end()) - a.begin());
#define  all(a)         a.begin(),a.end()

typedef  long long             ll;
typedef  long double           ld;
typedef  pair<ll,ll>           pll;
typedef  vector<ll>            vll;
typedef  vector<pll>           vpll;

const ll   N     =  5e5+5;
const ll   M     =  4e6+5;
const ll   mod   =  1e9+7;
const ll   INF   =  0x7f7f7f7f7f7f7f7f;
const int  INFi  =  0x7f7f7f7f;

int n, m, q, a[N], u[N], v[N], rem[N], X[N], Y[N];
int p[N], sz[N], l[N], r[N], ind[N];
vll adj[N];

struct NODE{
	int val, ind;
	NODE(): val(), ind() {}
	NODE(int v, int i): val(v), ind(i){}
};

NODE tree[4*N+8];

NODE combine(NODE a, NODE b){
	NODE c;
	c.val = max(a.val, b.val);
	if(c.val == a.val) c.ind = a.ind;
	else c.ind = b.ind;
	return c;
}

void build(int node, int p, int start, int end){
	if(start == end){
		tree[node] = NODE(a[adj[p][start-1]], start);
	}
	else{
		int mid = (start + end) / 2;
		build(2*node, p, start, mid);
		build(2*node+1, p, mid+1, end);
		tree[node] = combine(tree[2*node], tree[2*node+1]);
	}
}

void update(int node, int start, int end, int idx){
	if(start == end){
		tree[node] = NODE(0, idx);
	}
	else{
		int mid = (start + end) / 2;
		if(start <= idx and idx <= mid)
			update(2*node, start, mid, idx);
		else
			update(2*node+1, mid+1, end, idx);
		tree[node] = combine(tree[2*node], tree[2*node+1]);
	}
}

NODE query(int node, int start, int end, int l, int r){
	if(start > end or start > r or end < l)
		return NODE();
	if(l <= start and end <= r)
		return tree[node];
	int mid = (start + end) / 2;
	NODE p1 = query(2*node, start, mid, l, r);
	NODE p2 = query(2*node+1, mid+1, end, l, r);
	return combine(p1, p2);
}

void make(ll n){
	for(int i = 1; i <= n; i++){
		p[i] = i;
		sz[i] = 1;
		adj[i].pb(i);
	}
}

int find(ll x){
	return (p[x] == x)? x: p[x] = find(p[x]);
}

void merge(ll x, ll y){
	ll a = find(x);
	ll b = find(y);
	if(a != b){
		if(sz[a] >= sz[b]) swap(a,b);
		p[a] = b;
		sz[b] += sz[a];
		for(auto it : adj[a]) adj[b].pb(it);
		adj[a].clear();
	}
}

void solve(){
	cin >> n >> m >> q;
	make(n);
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= m; i++) cin >> u[i] >> v[i];
	for(int i = 1; i <= q; i++){
		cin >> X[i] >> Y[i];
		if(X[i] == 2) rem[Y[i]] = 1;
	}
	for(int i = 1; i <= m; i++){
		if(rem[i] == 1) continue;
		merge(u[i], v[i]);
	}
	for(int i = q; i >= 1; i--){
		if(X[i] == 2) merge(u[Y[i]], v[Y[i]]);
		else{
			int x = find(Y[i]);
			l[i] = adj[x].front(), r[i] = adj[x].back();
		}
	}
	for(int i = 2; i <= n; i++) merge(1, i);
	int p = find(1);
	for(int i = 0; i < n; i++) ind[adj[p][i]] = i+1;
	build(1, p, 1, n);
	for(int i = 1; i <= q; i++){
		if(X[i] == 2) continue;
		NODE c = query(1, 1, n, ind[l[i]], ind[r[i]]);
		if(c.ind) update(1, 1, n, c.ind);
		deb1(c.val)
	}
}

int main(){
	GODSPEED;
	int test = 1;
	//cin >> test;
	for(int i = 1; i <= test; i++){
		solve();
	}
}

#include <bits/stdc++.h>
using namespace std;using pr = pair<int, int>;int N, M, Q, A[200005], par[200005];pr E[300005], QS[500005];bool chk[300005];set<int> s[200005];stack<pr> st;
int f(int x) { return par[x] = (par[x] == x ? x : f(par[x])); }
void uni(int x, int y) {x = f(x), y = f(y);if(x == y) return;if(s[x].size() > s[y].size()) swap(x, y);st.push(pr(x, y));for(auto it : s[x]) s[y].insert(it);par[x] = y;}
int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> N >> M >> Q;iota(par, par + N + 1, 0);
	for(int i=1; i<=N; i++) cin >> A[i], s[i].insert(A[i]);for(int i=1, x, y; i<=M; i++) {cin >> x >> y;E[i] = pr(x, y);}
	for(int i=1, x, y; i<=Q; i++) {cin >> x >> y;QS[i] = pr(x, y);if(x == 2) chk[y] = 1;}
	for(int i=1; i<=M; i++) if(!chk[i]) uni(E[i].first, E[i].second);for(int i=Q; i; i--) {if(QS[i].first == 1)QS[i].second = f(QS[i].second);
		 else {int x = E[QS[i].second].first, y = E[QS[i].second].second;if(f(x) == f(y))QS[i].first = 0;else uni(x, y);}}
	for(int i=1; i<=Q; i++) {if(QS[i].first == 1) {int p = QS[i].second;int ans = 0;if(s[p].size() > 0) {ans = *s[p].rbegin();s[p].erase(ans);}cout << ans << "\n";
		} else if(QS[i].first == 2) {int x = st.top().first, y = st.top().second; st.pop();set<int> tmp;
			for(auto it : s[x]) if(s[y].find(it) != s[y].end()) {tmp.insert(it);s[y].erase(it);}s[x] = tmp;}}}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
#define F first
#define S second
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#ifdef dremix
    #define p(x) cerr<<#x<<" = "<<x<<endl;
    #define p2(x,y) cerr<<#x<<" , "<<#y<<" = "<<x<<" , "<<y<<endl;
    #define pp(x) cerr<<#x<<" = ("<<x.F<<" , "<<x.S<<")"<<endl;
    #define pv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u<<", ";cerr<<"}"<<endl;
    #define ppv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u.F<<"-"<<u.S<<", ";cerr<<"}"<<endl;
#else
    #define p(x)
    #define p2(x,y)
    #define pp(x)
    #define pv(x)
    #define ppv(x)
#endif
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxp = 22;
const ld EPS = 1e-18;
const ll INF = 1e18;
const int MOD = 1e9+7;
const int N = 4e5+1;

vector<vector<int> > nodes(N);
vector<int> par(N,0);

int find(int x){
    return (par[x]==x) ? x : par[x] = find(par[x]);
}

void join(int x, int y, vector<int> &v){
    x = find(x);
    y = find(y);
    if(x==y)return;
    if(nodes[x].size() < nodes[y].size())
        swap(x,y);

    v = nodes[y];
    for(int g : nodes[y])
        nodes[x].push_back(g);

    par[y] = x;
    nodes[y].clear();
}

int main(){
fastio

int n,m,q;
cin>>n>>m>>q;

int arr[n+1],i,inv[n+1];

for(i=1;i<=n;i++){
    cin>>arr[i];
    inv[arr[i]] = i;
    nodes[i].push_back(i);
}
pi edges[m+1];

for(i=1;i<=m;i++)
    cin>>edges[i].F>>edges[i].S;

pi ask[q];
bool rem[m+1] = {};

for(i=0;i<q;i++){
    cin>>ask[i].F>>ask[i].S;
    if(ask[i].F==2){
        rem[ask[i].S] = true;
    }
}

iota(all(par),0);

for(i=1;i<=m;i++){
    if(rem[i])continue;
    vector<int> fake;
    join(edges[i].F,edges[i].S,fake);
}

vector<vector<int> > save(q);

for(i=q-1;i>=0;i--){
    if(ask[i].F == 1)continue;
    int idx = ask[i].S;
    join(edges[idx].F,edges[idx].S,save[i]);
    p(i)
    pv(save[i])
}

vector<set<int> > s(N*2);

for(i=1;i<=n;i++){

    if(find(i)==i){
        p(i)
        pv(nodes[i])
        assert(!nodes[i].empty());
        for(auto x : nodes[i]){
            s[i].insert(arr[x]);
        }
        pv(s[i])
    }
}

int curr = n+1;

for(i=0;i<q;i++){
    if(ask[i].F == 1){
        int x = ask[i].S;
        x = find(x);
        p(x)
        pv(s[x])
        if(!s[x].empty()){
            auto it = s[x].end();
            it--;
            cout<<*it<<endl;
            arr[inv[*it]] = 0;
            s[x].erase(it);
        }
        else
            cout<<0<<endl;
    }
    else{
        if(save[i].empty())continue;
        int x = find(save[i][0]);
        pv(save[i])
        for(auto v : save[i]){
            s[x].erase(arr[v]);
            s[curr].insert(arr[v]);
            par[v] = curr;
        }
        curr++;
    }
}

}

// C++ 17
#include <bits/stdc++.h>
using namespace std;using pr = pair<int, int>;int N, M, Q, A[200005], par[200005];pr E[300005], QS[500005];bool chk[300005];set<int> s[200005];stack<pr> st;
int f(int x) { return par[x] = (par[x] == x ? x : f(par[x])); }
void uni(int x, int y) {x = f(x), y = f(y);if(x == y) return;if(s[x].size() > s[y].size()) swap(x, y);st.push(pr(x, y));for(auto it : s[x]) s[y].insert(it);par[x] = y;}
int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> N >> M >> Q;iota(par, par + N + 1, 0);
	for(int i=1; i<=N; i++) cin >> A[i], s[i].insert(A[i]);
	for(int i=1, x, y; i<=M; i++) {cin >> x >> y;E[i] = pr(x, y);}
	for(int i=1, x, y; i<=Q; i++) {cin >> x >> y;QS[i] = pr(x, y);if(x == 2) chk[y] = 1;}
	for(int i=1; i<=M; i++) if(!chk[i]) uni(E[i].first, E[i].second);
	for(int i=Q; i; i--) {
		if(QS[i].first == 1)QS[i].second = f(QS[i].second);
		 else {int x = E[QS[i].second].first, y = E[QS[i].second].second;if(f(x) == f(y))QS[i].first = 0;else uni(x, y);}}
	for(int i=1; i<=Q; i++) {
		if(QS[i].first == 1) {int p = QS[i].second;int ans = 0;if(s[p].size() > 0) {ans = *s[p].rbegin();s[p].erase(ans);}cout << ans << "\n";
		} else if(QS[i].first == 2) {
			int x = st.top().first, y = st.top().second; st.pop();set<int> tmp;
			for(auto it : s[x]) if(s[y].find(it) != s[y].end()) {tmp.insert(it);s[y].erase(it);}s[x] = tmp;}}}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
#define F first
#define S second
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#ifdef dremix
    #define p(x) cerr<<#x<<" = "<<x<<endl;
    #define p2(x,y) cerr<<#x<<" , "<<#y<<" = "<<x<<" , "<<y<<endl;
    #define pp(x) cerr<<#x<<" = ("<<x.F<<" , "<<x.S<<")"<<endl;
    #define pv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u<<", ";cerr<<"}"<<endl;
    #define ppv(x) cerr<<#x<<" = {";for(auto u : x)cerr<<u.F<<"-"<<u.S<<", ";cerr<<"}"<<endl;
#else
    #define p(x)
    #define p2(x,y)
    #define pp(x)
    #define pv(x)
    #define ppv(x)
#endif
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int maxp = 22;
const ld EPS = 1e-18;
const ll INF = 1e18;
const int MOD = 1e9+7;
const int N = 6e5+1;

vector<vector<int> > a(N);
vector<int> par(N);
int n;

int find(int x){
    return (par[x] == x) ? x : par[x] = find(par[x]);
}

void join(int x, int y){
    x = find(x);
    y = find(y);
    if(x==y)return;

    n++;
    par[x] = n;
    par[y] = n;
    par[n] = n;
    a[n].push_back(x);
    a[n].push_back(y);
}

int tin[N],tout[N];
int curr = 1;

void dfs(int s){
    tin[s] = curr++;
    for(auto x : a[s])
        dfs(x);
    tout[s] = curr;
}

pi seg[N*4];

void update(int s, int e, int idx, int k, int x){
    if(s==e && s==k){
        seg[idx] = {x,s};
        return;
    }
    if(s>k || e<k)return;
    int mid = (s+e)/2;
    update(s,mid,idx*2,k,x);
    update(mid+1,e,idx*2+1,k,x);

    seg[idx] = max(seg[idx*2],seg[idx*2+1]);
}

pi query(int s, int e, int idx, int qs, int qe){
    if(qs<=s && e<=qe)return seg[idx];
    if(s>qe || e<qs)return {0,0};
    int mid = (s+e)/2;

    return max(query(s,mid,idx*2,qs,qe),query(mid+1,e,idx*2+1,qs,qe));
}

int main(){
fastio

int m,q;
cin>>n>>m>>q;

int i,arr[n+1];

int ini = n;
for(i=1;i<=n;i++)cin>>arr[i];

pi edge[m+1];

for(i=1;i<=m;i++)cin>>edge[i].F>>edge[i].S;

for(i=1;i<=n;i++)par[i] = i;

pi ask[q];
bool rem[m+1]={};

for(i=0;i<q;i++){
    cin>>ask[i].F>>ask[i].S;
    if(ask[i].F==2){
        rem[ask[i].S] = true;
    }
}

for(i=1;i<=m;i++){
    if(rem[i])continue;
    join(edge[i].F,edge[i].S);
}

vector<int> ans;

for(i=q-1;i>=0;i--){
    if(ask[i].F==1){
        ans.push_back(find(ask[i].S));
    }
    else{
        join(edge[ask[i].S].F,edge[ask[i].S].S);
    }
}

for(i=1;i<=n;i++){
    if(find(i)==i){
        //cout<<i<<endl;
        dfs(i);
    }
}

for(i=1;i<=n;i++){
    p2(tin[i],tout[i])
}

for(i=1;i<=ini;i++){
    p2(tin[i],arr[i])
    update(1,n,1,tin[i],arr[i]);
}

reverse(all(ans));
pv(ans)
p(n)

for(auto x : ans){
    p2(tin[x],tout[x]-1)
    p(x)

    pi res = query(1,n,1,tin[x],tout[x]-1);
    pp(res)
    cout<<res.F<<endl;
    if(res.S)
        update(1,n,1,res.S,0);
}

}

// code by a weak man named YJJ
#include <bits/stdc++.h>
#define filesolution freopen("data.in", "r", stdin), freopen("solution.out", "w", stdout)
#define filebrute freopen("data.in", "r", stdin), freopen("brute.out", "w", stdout)
#define filemakedata freopen("data.in", "w", stdout);
#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
using namespace std;

template <typename T> void read(T &x) {
  x = 0; int f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = x * 10 + (ch ^ 48);
    ch = getchar();
  }
  return x *= f, void();
}
template <typename T> void ckmax(T &a, T b) { a = b > a ? b : a; }
template <typename T> void ckmin(T &a, T b) { a = b < a ? b : a; }

///////////////////////////////////////////////////

#define ls p << 1
#define rs p << 1 | 1
#define mid ((l + r) >> 1)

const int N = 5e5 + 5;

int n, m, q, tot, U[N], V[N], del[N], fa[N], p[N], op[N], x[N], dfn[N], cnt, siz[N];
vector<int> g[N];
pair<int, int> w[N << 2];

inline void pushup(int p) {
  w[p] = max(w[ls], w[rs]);
}

void modify(int p, int l, int r, int x, int val) {
//  printf("modify(%d, %d, %d, %d, %d)\n", p, l, r, x, val);
  if (l == r) return w[p] = make_pair(val, l), void();
  if (x <= mid) modify(ls, l, mid, x, val);
  else modify(rs, mid + 1, r, x, val);
  pushup(p);
}

pair<int, int> query(int p, int l, int r, int x, int y) {
//  printf("query(%d, %d, %d, %d, %d)\n", p, l, r, x, y);
  if (y == 0) return make_pair(0, 0);
  if (x <= l && r <= y) return w[p];
  pair<int, int> res(0, 0);
  if (x <= mid) res = max(res, query(ls, l, mid, x, y));
  if (y > mid) res = max(res, query(rs, mid + 1, r, x, y));
  return res;
}

int find(int u) {
  if (fa[u] == u) return u;
  return fa[u] = find(fa[u]);
}

inline void merge(int u, int v) {
//  printf("merge(%d, %d)\n", u, v);
  u = find(u), v = find(v);
  if (u == v) return ;
  fa[u] = fa[v] = ++tot;
  fa[tot] = tot;
  g[tot].push_back(u);
  g[tot].push_back(v);
}

void dfs(int u) {
//  printf("dfs(%d)\n", u);
  dfn[u] = ++cnt, siz[u] = 1;
  if (u <= n) modify(1, 1, tot, dfn[u], p[u]);
  for (auto v : g[u]) {
    if (dfn[v]) continue;
    dfs(v), siz[u] += siz[v];
  }
}

int main() {
  read(n), read(m), read(q), tot = n;
  for (int i = 1; i <= n; i++) read(p[i]);
  for (int i = 1; i <= m; i++) read(U[i]), read(V[i]);
  for (int i = 1; i <= q; i++) {
    read(op[i]), read(x[i]);
    if (op[i] == 2) del[x[i]] = 1;
  }
  for (int i = 1; i <= n; i++) fa[i] = i;
  for (int i = 1; i <= m; i++) {
    if (!del[i]) merge(U[i], V[i]);
  }
  for (int i = q; i >= 1; i--) {
    if (op[i] == 2) {
      merge(U[x[i]], V[x[i]]);
    } else {
      x[i] = find(x[i]);
    }
  }
  ++tot;
  for (int i = 1; i < tot; i++) {
    if (fa[i] == i) {
      g[tot].push_back(i);
    }
  }
  dfs(tot);
  for (int i = 1; i <= q; i++) {
    if (op[i] == 1) {
      pair<int, int> ans;
      ans = query(1, 1, tot, dfn[x[i]], dfn[x[i]] + siz[x[i]] - 1);
      printf("%d\n", ans.first);
      modify(1, 1, tot, ans.second, 0);
    }
  }
  return 0;
}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,r,l) for(int i=(r);i>=(l);--i)
#define For(i,u) for(int i=hed[u],v=e[i].to;i;i=e[i].nex,v=e[i].to)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int N=5e5+10;
int f[N],sz[N],hed[N],ed,n,m,Q,id[N],opt[N],a[N],u[N],v[N],del[N],p[N];
set<pair<int,int> > s[N];bool ban[N];
struct edge{
	int to,nex;bool vis;
	edge(int _=0,int __=0):to(_),nex(__),vis(0){}
}e[N<<1];
inline void add(int u,int v){e[++ed]=edge(v,hed[u]);hed[u]=ed;}
int gfa(int x){return f[x]^x?(f[x]=gfa(f[x])):x;}
void merge(int u,int v){u=gfa(u);v=gfa(v);if(sz[u]>=sz[v]) swap(u,v);f[u]=v;sz[v]+=sz[u];}
void dfs(int u,int fa,int x,int y){
	f[u]=x;s[y].erase(mp(a[u],u));s[x].insert(mp(a[u],u));
	For(i,u) if((v^fa)&&!e[i].vis) dfs(v,u,x,y);
}
int main(){
	scanf("%d%d%d",&n,&m,&Q);ed=1;
	rep(i,1,n) scanf("%d",a+i),f[i]=i,sz[i]=1;
	rep(i,1,m) scanf("%d%d",u+i,v+i);
	rep(i,1,Q) scanf("%d%d",opt+i,id+i);
	rep(i,1,Q) if(opt[i]==2) ban[id[i]]=1;
	rep(i,1,m) if(gfa(u[i])^gfa(v[i])&&!ban[i]) merge(u[i],v[i]),add(u[i],v[i]),add(v[i],u[i]);
	per(i,Q,1) if(opt[i]==2&&(gfa(u[id[i]])^gfa(v[id[i]]))){
		int x=gfa(u[id[i]]),y=gfa(v[id[i]]);
		add(u[id[i]],v[id[i]]),add(v[id[i]],u[id[i]]);
		del[i]=sz[x]<sz[y]?ed:ed-1;p[i]=sz[x]<sz[y]?x:y;merge(x,y);
	}
	rep(i,1,n) s[gfa(i)].insert(mp(a[i],i));
	rep(i,1,Q){
		if(opt[i]==1){
			int u=gfa(id[i]),x=s[u].rbegin()->se;
			printf("%d\n",a[x]);a[x]=0;
			s[u].erase(*s[u].rbegin());s[u].insert(mp(0,x));
		}
		else if(del[i]){
			int x=e[del[i]].to;e[del[i]].vis=e[del[i]^1].vis=1;
			dfs(x,0,p[i],gfa(x));
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],bel[200005],a[200005],used[200005];
vector<int> h[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
inline int Query(int x)
{
	while(h[x].size()&&(bel[h[x].back()]!=x||used[h[x].back()])) h[x].pop_back();
	if(!h[x].size()) return 0;
	int ans=h[x].back();
	h[x].pop_back(),used[ans]=1;
	return ans;
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1,x;i<=n;i++)scanf("%d",&x),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for ( int i=1;i<=m;i++ ) if(!del[i])
	{
		int fx=gf(ex[i]),fy=gf(ey[i]);
		if(fx==fy) continue;
		if(sz[fx]>sz[fy]) swap(fx,fy);
		for ( int j=0;j<h[fx].size();j++ ) h[fy].push_back(h[fx][j]);
		fa[fx]=fy,sz[fy]+=sz[fx];
	}
	for ( int i=Q;i>=1;i-- )
	{
		int op=q[i].opt,x=q[i].x;
		int fx=gf(ex[x]),fy=gf(ey[x]);
		if(fx==fy||op==1) continue;
		if(sz[fx]>sz[fy]) swap(fx,fy);
		fa[fx]=fy,sz[fy]+=sz[fx],q[i].rx=fx;
		for ( int j=0;j<h[fx].size();j++ ) h[fy].push_back(h[fx][j]);
	}
	for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end()),bel[a[i]]=gf(i);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for ( int j=0;j<h[q[i].rx].size();j++ ) bel[h[q[i].rx][j]]=q[i].rx;
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],bel[200005],a[200005],used[200005];
vector<int> h[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
inline int Query(int x)
{
	while(h[x].size()&&(bel[h[x].back()]!=x||used[h[x].back()])) h[x].pop_back();
	if(!h[x].size()) return 0;
	int ans=h[x].back();
	h[x].pop_back(),used[ans]=1;
	return ans;
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1,x;i<=n;i++)scanf("%d",&x),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for ( int i=1;i<=m;i++ ) if(!del[i])
	{
		int fx=gf(ex[i]),fy=gf(ey[i]);
		if(fx==fy) continue;
		if(sz[fx]>sz[fy]) swap(fx,fy);
		for ( int j=0;j<h[fx].size();j++ ) h[fy].push_back(h[fx][j]);
		fa[fx]=fy,sz[fy]+=sz[fx];
	}
	for(int i=1;i<=m;i++){
		if(del[i])continue;
		int x=gf(ex[i]),y=gf(ey[i]);
		if(x==y)continue;
		if(sz[x]>sz[y])swap(x,y);
		for ( int j=0;j<h[x].size();j++ ) h[y].push_back(h[x][j]);
		fa[x]=y,sz[y]+=sz[x];
	}
	for(int i=Q;i>=1;i--){
		int x=ex[q[i].x],y=ey[q[i].x];
		if(q[i].opt==1||gf(x)==gf(y))continue;
		x=gf(x),y=gf(y);
		if(sz[x]>sz[y])swap(x,y);
		q[i].rx=x,fa[x]=y,sz[y]+=sz[x];
		for ( int j=0;j<h[x].size();j++ ) h[y].push_back(h[x][j]);
	}
	for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end()),bel[a[i]]=gf(i);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for ( int j=0;j<h[q[i].rx].size();j++ ) bel[h[q[i].rx][j]]=q[i].rx;
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx,avx2,fma")
#include <bits/stdc++.h>

using std::cin;
using std::cout;
using std::vector;
using std::string;
using ll = long long;
using real = long double;
using u64t = uint64_t;
using vi = vector<int>;
using vell = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vell>;
using pii = std::pair<int, int>;
using pll = std::pair<ll, ll>;
using vpii = vector<pii>;
using vpll = vector<pll>;
using vchar = vector<char>;
using vvchar = vector<vchar>;
#define isz(x) (int)(x).size()
#define all(x) begin(x), end(x)
#define forx(x, n) for(int x = 0; x < n; ++x)
#define forx1(x, n) for(int x = 1; x <= n; ++x)
#define fill(v, n) for(int i = 0; i < n; ++i) cin >> v[i];
const ll mod = 1e9 + 7;

ll fast_multip(ll a, ll b, ll m)
{
	if (!a || !b) return 0;
	if (b == 1) return a;
	if (a == 1) return b;
	if (b % 2 == 0) {
		long long t = fast_multip(a, b / 2, m);
		return (2 * t) % m;
	}
	return (fast_multip(a, b - 1, m) + a) % m;
}

ll fast_pow(ll a, ll b, ll m)
{
	if (b == 0)
		return (m == 1) ? 0 : 1;
	if (b % 2 == 0) {
		ll t = fast_pow(a, b / 2, m);
		return fast_multip(t, t, m) % m;
	}
	return (fast_multip(fast_pow(a, b - 1, m), a, m)) % m;
}

ll inv(ll a)
{
	return fast_pow(a, mod - 2, mod);
}

const auto ready = []()
{
	cin.tie(0);
	cout.tie(0);
	std::ios_base::sync_with_stdio(false);
	return true;
}();

template<class A, class B>
void remin(A &a, const B &b)
{
	a = (a < b) ? a : b;
}

template<class A, class B>
void remax(A &a, const B &b)
{
	a = (a > b) ? a : b;
}

ll gcd(ll a, ll b, ll & x, ll & y) {
	if (a == 0) {
		x = 0; y = 1;
		return b;
	}
	ll x1, y1;
	ll d = gcd(b%a, a, x1, y1);
	x = y1 - (b / a) * x1;
	y = x1;
	return d;
}

vi par;
vi sz;

int getParent(int x)
{
	if (par[x] == x) return x;
	return par[x] = getParent(par[x]);
}

struct decomp
{
	bool bridge = false;
	int lessComp;
	int lessCompSize;
};

void unite(int x, int y, decomp& cur, bool fictive = true)
{
	int par1 = getParent(x), par2 = getParent(y);
	if (par1 == par2) return;
	if (sz[par1] > sz[par2]) std::swap(x, y), std::swap(par1, par2);
	par[par1] = par2;
	if(!fictive) cur.bridge = true;
	if(!fictive) cur.lessComp = x;
	if (!fictive) cur.lessCompSize = sz[par1];
	sz[par2] += sz[par1];
}

vector<std::list<pii>> st;
vector<std::list<pii>::iterator> listIters;
vector<std::set<int>> adj, adj2;
vi p;
vi belongsTo;
int freeNum = 1;

std::list<pii> ficitveList;
static vi toDelete;
static vpii toNewList;
std::bitset<int(2e5 + 10)> used2;
void divide(int x, int y, decomp& cur)
{
    toDelete.clear();
    toNewList.clear();
	int small = cur.lessComp;
	assert(small == x || small == y);
	int smallSize = cur.lessCompSize;
	//cout << small << " " << smallSize << "\n";
	int largeNum = belongsTo[small];
	std::queue<int> q;
	q.push(small);
	used2[small] = 1;
	while(q.size())
	{
	    int u = q.front(); q.pop();
	    toDelete.push_back(u);
	    for(auto &v : adj2[u])
	    {
	        if(!used2[v]) used2[v] = 1, q.push(v);
	    }
	}
	used2 = 0;
	for (auto &item : toDelete) belongsTo[item] = freeNum;
	for(auto &item : toDelete)
	{
	    auto it = listIters[item];
	    if(it == ficitveList.end()) continue;
	    toNewList.push_back(*it);
	    st[largeNum].erase(it);
	}
	std::sort(all(toNewList));
	for(auto &item : toNewList) st[freeNum].push_back(item);
	for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
	++freeNum;
}

int main()
{
    toDelete.reserve(2e5 + 10);
    toNewList.reserve(2e5 + 10);
	int n, m, q; cin >> n >> m >> q;
	par.resize(n + 1);
	std::iota(all(par), 0);
	belongsTo.resize(n + 1);
	st.resize(n + 2);
	sz.resize(n + 1, 1);
	listIters.resize(n + 2);
	p.resize(n + 1);
	adj.resize(n + 1);
	adj2.resize(n + 1);
	for (int u = 1; u <= n; ++u) cin >> p[u];
	vpii edges(m + 1);
	forx(i, m)
	{
		int u, v; cin >> u >> v;
		adj[u].insert(v); adj[v].insert(u);
		adj2[u].insert(v); adj2[v].insert(u);
		edges[i + 1] = { u, v };
	}
	vpii order(q);
	int deletedEdges = 0;
	forx(i, q)
	{
		int u, v; cin >> u >> v;
		order[i] = { u, v };
		if (u == 2) ++deletedEdges;
	}
	vector<decomp> events(deletedEdges);
	// Unite all after deleting edges
	for (auto &req : order)
	{
		if (req.first == 2)
		{
			auto it = edges[req.second];
			int u = it.first, v = it.second;
			adj[u].erase(v); adj[v].erase(u);
		}
	}
	decomp tmp{};
	for (int u = 1; u <= n; ++u) for (auto &v : adj[u]) unite(u, v, tmp);
	int ptr = 0;
	for (int i = order.size() - 1; i >= 0; --i)
	{
		if (order[i].first == 2)
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			unite(u, v, events[ptr], false);
			++ptr;
		}
	}
	std::reverse(all(events));
	vi used(n + 1, 0);
	vi curComponent;
	std::function<void(int)> dfs = [&](int u)
	{
		used[u] = 1;
		curComponent.push_back(u);
		for (auto &v : adj2[u]) if (!used[v]) dfs(v);
	};
	for (int u = 1; u <= n; ++u)
	{
		if (!used[u])
		{
			curComponent.clear();
			dfs(u);
			vpii tmp;
			for(auto &item : curComponent) tmp.push_back({p[item], item});
			std::sort(all(tmp));
			for(auto &item : tmp) st[freeNum].push_back(item);
			for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
			for (auto &item : curComponent) belongsTo[item] = freeNum;
			++freeNum;
		}
	}
	ptr = 0;
	forx(i, q)
	{
		if (order[i].first == 1)
		{
			int u = order[i].second;
			auto& curSet = st[belongsTo[u]];
			if (curSet.size())
			{
				auto it = --curSet.end();
				cout << it->first << "\n";
				listIters[it->second] = ficitveList.end();
				curSet.erase(it);
			}
			else cout << 0 << "\n";
		}
		else
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			adj2[u].erase(v); adj2[v].erase(u);
			if(events[ptr].bridge) divide(u, v, events[ptr]);
			++ptr;
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
const int mod=1e9+7;
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
typedef long long ll;
typedef double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
ll qpow(ll a,ll b){ll ans=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)ans=ans*a%mod;a=a*a%mod;}return ans;}
ll gcd(ll a,ll b){return b>0?gcd(b,a%b):a;}
int n,m,T,N;
int pre[maxn],a[maxn],p[maxn];
int Find(int x){
	return pre[x]==x?x:pre[x]=Find(pre[x]);
}
struct QUERY{
	int o,x,t;
}q[maxn];

struct Edge{
	int u,v;
}e[maxn];

int flag[maxn];
int rmq[maxn][35];
vi g[maxn];
int L[maxn],R[maxn],d[maxn],tot;
bool bk[maxn];
void dfs(int u){
	flag[u]=1;
	if(d[u]){
		a[++tot]=d[u];
		L[u]=tot;
	}
	else L[u]=tot+1;
	for(auto v:g[u]){
		dfs(v);
	}
	R[u]=tot;
}
void init(){
	for(int i=1;i<=n;i++) pre[i]=i,d[i]=i,rmq[i][0]=i;
	for(int i=1;i<=m;i++){
		if(flag[i])continue;
		int fax=Find(e[i].u);
		int fay=Find(e[i].v);
		if(fax==fay) continue;
		rmq[fax][0]=fay;
		pre[fax]=fay;
		g[fay].pb(fax);
	}
	N=n;
	for(int i=T;i>=1;i--){
		if(q[i].o==1)continue;
		int fax=Find(e[q[i].x].u);
		int fay=Find(e[q[i].x].v);
		if(fax==fay)continue;
		++N;
		pre[N]=N;
		rmq[N][0]=N;
		bk[i]=1;
		rmq[fax][0]=N;
		rmq[fay][0]=N;
		pre[fax]=N;
		pre[fay]=N;
		g[N].pb(fax);
		g[N].pb(fay);
	}
	for(int bit=1;bit<=30;bit++){
		for(int i=1;i<=N;i++){
			rmq[i][bit]=rmq[rmq[i][bit-1]][bit-1];
		}
	}
	memset(flag,0,sizeof flag);
	tot=0;
	for(int i=N;i>=1;i--){
		if(flag[i])continue;
		dfs(i);
	}
}
pii tr[maxn<<2];
#define lson rt<<1
#define rson rt<<1|1
void build(int l,int r,int rt){
	 if(l==r){
	 	tr[rt]={p[a[l]],l};
	 	return;
	 }
	 int mid=l+r>>1;
	 build(l,mid,lson);
	 build(mid+1,r,rson);
	 tr[rt]=max(tr[lson],tr[rson]);
}
void update(ll C,int pos,int l,int r,int rt){
	if(pos<l||pos>r) return;
	if(l==r){
		tr[rt]={C,l};
		return;
	}
	int mid=l+r>>1;
	update(C,pos,l,mid,lson);
	update(C,pos,mid+1,r,rson);
	tr[rt]=max(tr[lson],tr[rson]);
}
pii query(int L,int R,int l,int r,int rt){
	if(r<L||R<l) return {0,0};
	if(L<=l&&r<=R){
		return tr[rt];
	}
	int mid=l+r>>1;
	return max(query(L,R,l,mid,lson),query(L,R,mid+1,r,rson));
}
int main() {
	cin>>n>>m>>T;
	for(int i=1;i<=n;i++) cin>>p[i];
	for(int i=1;i<=m;i++){
		scanf("%d%d",&e[i].u,&e[i].v);
	}
	for(int i=1;i<=T;i++){
		scanf("%d%d",&q[i].o,&q[i].x);
		q[i].t=i;
		if(q[i].o==2) flag[q[i].x]=1;
	}
	init();
	memset(flag,0,sizeof flag);
	build(1,N,1);
	for(int i=1;i<=T;i++){
		if(q[i].o==1){
			int now=q[i].x;
			for(int bit=30;bit>=0;bit--){
				int to=rmq[now][bit];
				if(flag[to])continue;
				now=to;
			}
			pii res=query(L[now],R[now],1,N,1);
			cout<<res.fi<<"\n";
			update(0,res.se,1,N,1);
		}else if(bk[i]){
			int now=e[q[i].x].u;
			for(int bit=30;bit>=0;bit--){
				int to=rmq[now][bit];
				if(flag[to])continue;
				now=to;
			}
			flag[now]=1;
		}
	}
	return 0;
}
/*
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
*/

#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

const int N = 200005;
const int M = 300005;
const int Q = 500005;

int n, m, q, ori;
int ea[M], eb[M], er[M];
int type[Q], qu[Q];
int c[N+N];
int dup[N+N][20];
int par[N+N];

vector<int> g[N+N];
int in[N+N], out[N+N], dfs_t;

void dfs(int u) {
	if(u <= ori) {
		in[u] = ++dfs_t;
		out[u] = dfs_t;
		return;
	}
	in[u] = -1;
	for(int v : g[u]) {
		dfs(v);
		if(in[u] == -1) in[u] = in[v];
	}
	out[u] = dfs_t;
}

int f(int u) {
	return u == par[u] ? u : par[u] = f(par[u]);
}

int get_root(int u, int ti) {

	for(int j = 19; j >= 0; j--) {
		if(c[ dup[u][j] ] > ti) {
			u = dup[u][j];
		}
	}
	return u;
}

int st[2*N];

void upd(int x, int val) {
	x--;
	st[x += ori] = val;
	while(x >>= 1) st[x] = max(st[2 * x], st[2 * x + 1]);
}
int query(int l, int r) {
	l--, r--;
	int ans = 0;
	for(l += ori, r += ori + 1; l < r; l >>= 1, r >>= 1) {
		if(l & 1) ans = max(ans, st[l++]);
		if(r & 1) ans = max(ans, st[--r]);
	}
	return ans;
}

int p[N], rp[N];

int main() {
	scanf("%d %d %d", &n, &m, &q);
	ori = n;

	for(int i = 1; i <= n; i++) scanf("%d", p + i);

	for(int i = 1; i <= m; i++) {
		scanf("%d %d", ea + i, eb + i);
	}

	for(int i = 0; i < q; i++) {
		scanf("%d %d", type + i, qu + i);
		if(type[i] == 2) er[ qu[i] ] = 1;
	}

	for(int i = 1; i <= n; i++) par[i] = i, c[i] = q;

	for(int i = 1; i <= m; i++) if(!er[i]) {
		int a = f(ea[i]), b = f(eb[i]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = q;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = q - 1; i >= 0; i--) if(type[i] == 2) {
		int a = f(ea[ qu[i] ]), b = f(eb[ qu[i] ]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = i;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = 2; i <= ori; i++) if(f(i) != f(1)) {
		int a = f(1), b = f(i);
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = -1;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	dup[n][0] = n;

	for(int lvl = 0; lvl + 1 < 20; lvl++) {
		for(int i = 1; i <= n; i++) {
			dup[i][lvl + 1] = dup[ dup[i][lvl] ][lvl];
		}
	}

	dfs(n);

	for(int i = 1; i <= ori; i++) {
		upd(in[i], p[i]);
		rp[ p[i] ] = in[i];
	}

	for(int i = 0; i < q; i++) {
		if(type[i] == 1) {
			int r = get_root(qu[i], i);
			int val = query(in[r], out[r]);
			printf("%d\n", val);
			if(val) upd(rp[val], 0);
		}
	}
}

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
namespace FastIO {
    struct Reader {
    private:
        FILE* file; std::vector<char> buffer; int pos; bool was;
        void read() {
            if (!buffer.empty()) {
                buffer.resize(fread(&buffer[0], 1, (int)buffer.size(), file)); pos = 0;
            }
        }
    public:
        Reader(FILE* file_ = stdin, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(size_), was(true) { }
        operator bool() const { return was; }
        char getChar() {
            if (pos == (int)buffer.size()) { read(); }
            if (pos == (int)buffer.size()) { was = false; return EOF; }
            else { was = true; return buffer[pos++]; }
        }
        std::string getStr() {
            char c = ' ';
            while (std::isspace(c)) { c = getChar(); }
            std::string answ;
            while (c != EOF && !std::isspace(c)) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        std::string getLine() {
            char c = '\n';
            while (c == '\n') { c = getChar(); }
            std::string answ;
            while (c != '\n' && c != EOF) { answ.push_back(c); c = getChar(); }
            was = !answ.empty();
            return answ;
        }
        template<typename T> T getInt() {
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = true;
            if (c == '-') { positive = false; c = getChar(); }
            T answ(0);
            bool flag = false;
            while ('0' <= c && c <= '9') { flag = true; (answ *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            return positive ? answ : -answ;
        }
        template<typename T> T getReal() {
            bool flag = false;
            char c = '?';
            while (!(c == '-' || ('0' <= c && c <= '9') || c == EOF)) { c = getChar(); }
            bool positive = (c != '-');
            if (c == '-') { c = getChar(); }
            long long first = 0;
            while ('0' <= c && c <= '9') { flag = true; (first *= 10) += (c - '0'); c = getChar(); }
            was = flag;
            if (c != '.') { return T(positive ? first : -first); }
            c = getChar();
            long long second = 0, pow = 1;
            while ('0' <= c && c <= '9') { (second *= 10) += (c - '0'); c = getChar(); pow *= 10; }
            T answ = first + (T)second / (T)pow;
            return positive ? answ : -answ;
        }
    };

    Reader& operator>>(Reader& reader, char& c) { return c = reader.getChar(), reader; }

    Reader& operator>>(Reader& reader, std::string& s) { return s = reader.getStr(), reader; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getReal<T>(), reader; }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Reader&>::type
    operator>>(Reader& reader, T& t) { return t = reader.getInt<T>(), reader; }

    template<class T> Reader& operator>>(Reader& reader, std::vector<T>& vec) {
        for (auto &it : vec) { reader >> it; }
        return reader;
    }

    struct Writer {
    private:
        FILE* file; std::vector<char> buffer; int pos;
        int defaultPrecision, defaultWidth; char defaultFill;
    public:
        Writer(FILE* file_ = stdout, const int size_ = 1 << 16)
            : file(file_), buffer(size_, '\0'), pos(0), defaultPrecision(6), defaultWidth(0), defaultFill(' ') { }
        ~Writer() { flush(); }
        void flush() { putChar(EOF); }
        void setprecision(int precision) { defaultPrecision = precision; }
        void setw(int width) { defaultWidth = width; }
        void setfill(char fill) { defaultFill = fill; }
        int getPrecision() const { return defaultPrecision; }
        int getWidth() const { return defaultWidth; }
        char getFill() const { return defaultFill; }
        void putChar(char c) {
            if (pos == (int)buffer.size() || c == EOF) {
                fwrite(&buffer[0], 1, pos, file); pos = 0;
            }
            if (c != EOF) { buffer[pos++] = c; }
        }
        void putStr(const std::string& s) { for (auto it : s) putChar(it); }
        template<typename T> void putInt(T value, int width = 0, char fill = ' ') {
            bool positive = !(value < 0);
            if (value < 0) { value = -value; }
            char buf[24]; int p = 0;
            do { buf[p++] = char(value % 10 + '0'); value /= 10; } while (value > 0);
            if (!positive) { buf[p++] = '-'; }
            while (p < width) buf[p++] = fill;
            while (p > 0) putChar(buf[--p]);
        }
        template<typename T> void putReal(T value, int precision = 6, int width = 0, char fill = ' ') {
            putInt((long long)value, width - precision - 1, fill);
            value = std::abs(value-(long long)value);
            if (precision == 0) { return; }
            putChar('.');
            #define PRINT_PART(cnt, pow) \
                while (precision >= cnt) { \
                    value *= pow; \
                    putInt((int)value, cnt, '0'); \
                    value -= (int)value; \
                    precision -= cnt; \
                }
            PRINT_PART(6,1000000)
            PRINT_PART(3,1000)
            PRINT_PART(1,10)
            #undef PRINT_PART
        }
    };

    Writer& operator<<(Writer& writer, const char c) { return writer.putChar(c), writer; }

    Writer& operator<<(Writer& writer, const std::string& s) { return writer.putStr(s), writer; }

    template<class T> typename std::enable_if<std::is_floating_point<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putReal(t, writer.getPrecision(), writer.getWidth(), writer.getFill());
        return writer;
    }

    template<class T> typename std::enable_if<std::is_integral<T>::value, Writer&>::type
    operator<<(Writer& writer, const T& t) {
        writer.putInt(t, writer.getWidth(), writer.getFill());
        return writer;
    }
}

using std::vector;
using std::string;
using ll = long long;
using real = long double;
using u64t = uint64_t;
using vi = vector<int>;
using vell = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vell>;
using pii = std::pair<int, int>;
using pll = std::pair<ll, ll>;
using vpii = vector<pii>;
using vpll = vector<pll>;
using vchar = vector<char>;
using vvchar = vector<vchar>;
#define isz(x) (int)(x).size()
#define all(x) begin(x), end(x)
#define forx(x, n) for(int x = 0; x < n; ++x)
#define forx1(x, n) for(int x = 1; x <= n; ++x)
#define fill(v, n) for(int i = 0; i < n; ++i) cin >> v[i];
const ll mod = 1e9 + 7;

template<class A, class B>
void remin(A &a, const B &b)
{
	a = (a < b) ? a : b;
}

template<class A, class B>
void remax(A &a, const B &b)
{
	a = (a > b) ? a : b;
}

ll gcd(ll a, ll b, ll & x, ll & y) {
	if (a == 0) {
		x = 0; y = 1;
		return b;
	}
	ll x1, y1;
	ll d = gcd(b%a, a, x1, y1);
	x = y1 - (b / a) * x1;
	y = x1;
	return d;
}

vi par;
vi sz;

int getParent(int x)
{
	if (par[x] == x) return x;
	return par[x] = getParent(par[x]);
}

struct decomp
{
	bool bridge = false;
	int lessComp;
	int lessCompSize;
};

void unite(int x, int y, decomp& cur, bool fictive = true)
{
	int par1 = getParent(x), par2 = getParent(y);
	if (par1 == par2) return;
	if (sz[par1] > sz[par2]) std::swap(x, y), std::swap(par1, par2);
	par[par1] = par2;
	if(!fictive) cur.bridge = true;
	if(!fictive) cur.lessComp = x;
	if (!fictive) cur.lessCompSize = sz[par1];
	sz[par2] += sz[par1];
}

vector<std::list<pii>> st;
vector<std::list<pii>::iterator> listIters;
vector<std::set<int>> adj, adj2;
vi p;
vi belongsTo;
int freeNum = 1;

std::list<pii> ficitveList;
static vi toDelete;
static vpii toNewList;
void divide(int x, int y, decomp& cur)
{
    toDelete.clear();
    toNewList.clear();
	int small = cur.lessComp;
	assert(small == x || small == y);
	int smallSize = cur.lessCompSize;
	//cout << small << " " << smallSize << "\n";
	int largeNum = belongsTo[small];
	std::unordered_map<int, int> used;
	std::queue<int> q;
	q.push(small);
	used[small] = 1;
	while(q.size())
	{
	    int u = q.front(); q.pop();
	    toDelete.push_back(u);
	    for(auto &v : adj2[u])
	    {
	        if(!used[v]) used[v] = 1, q.push(v);
	    }
	}
	for (auto &item : toDelete) belongsTo[item] = freeNum;
	for(auto &item : toDelete)
	{
	    auto it = listIters[item];
	    if(it == ficitveList.end()) continue;
	    toNewList.push_back(*it);
	    st[largeNum].erase(it);
	}
	std::sort(all(toNewList));
	for(auto &item : toNewList) st[freeNum].push_back(item);
	for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
	++freeNum;
}

int main()
{
    FastIO::Reader cin;
    FastIO::Writer cout;
    toDelete.reserve(2e5 + 10);
    toNewList.reserve(2e5 + 10);
	int n, m, q; cin >> n >> m >> q;
	par.resize(n + 1);
	std::iota(all(par), 0);
	belongsTo.resize(n + 1);
	st.resize(n + 2);
	sz.resize(n + 1, 1);
	listIters.resize(n + 2);
	p.resize(n + 1);
	adj.resize(n + 1);
	adj2.resize(n + 1);
	for (int u = 1; u <= n; ++u) cin >> p[u];
	vpii edges(m + 1);
	forx(i, m)
	{
		int u, v; cin >> u >> v;
		adj[u].insert(v); adj[v].insert(u);
		adj2[u].insert(v); adj2[v].insert(u);
		edges[i + 1] = { u, v };
	}
	vpii order(q);
	int deletedEdges = 0;
	forx(i, q)
	{
		int u, v; cin >> u >> v;
		order[i] = { u, v };
		if (u == 2) ++deletedEdges;
	}
	vector<decomp> events(deletedEdges);
	// Unite all after deleting edges
	for (auto &req : order)
	{
		if (req.first == 2)
		{
			auto it = edges[req.second];
			int u = it.first, v = it.second;
			adj[u].erase(v); adj[v].erase(u);
		}
	}
	decomp tmp{};
	for (int u = 1; u <= n; ++u) for (auto &v : adj[u]) unite(u, v, tmp);
	int ptr = 0;
	for (int i = order.size() - 1; i >= 0; --i)
	{
		if (order[i].first == 2)
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			unite(u, v, events[ptr], false);
			++ptr;
		}
	}
	std::reverse(all(events));
	vi used(n + 1, 0);
	vi curComponent;
	std::function<void(int)> dfs = [&](int u)
	{
		used[u] = 1;
		curComponent.push_back(u);
		for (auto &v : adj2[u]) if (!used[v]) dfs(v);
	};
	for (int u = 1; u <= n; ++u)
	{
		if (!used[u])
		{
			curComponent.clear();
			dfs(u);
			vpii tmp;
			for(auto &item : curComponent) tmp.push_back({p[item], item});
			std::sort(all(tmp));
			for(auto &item : tmp) st[freeNum].push_back(item);
			for(auto it = st[freeNum].begin(); it != st[freeNum].end(); ++it) listIters[(*it).second] = it;
			for (auto &item : curComponent) belongsTo[item] = freeNum;
			++freeNum;
		}
	}
	ptr = 0;
	forx(i, q)
	{
		if (order[i].first == 1)
		{
			int u = order[i].second;
			auto& curSet = st[belongsTo[u]];
			if (curSet.size())
			{
				auto it = --curSet.end();
				cout << it->first << "\n";
				listIters[it->second] = ficitveList.end();
				curSet.erase(it);
			}
			else cout << 0 << "\n";
		}
		else
		{
			auto it = edges[order[i].second];
			int u = it.first, v = it.second;
			adj2[u].erase(v); adj2[v].erase(u);
			if(events[ptr].bridge) divide(u, v, events[ptr]);
			++ptr;
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define fst first
#define snd second
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define for_tests(t, tt) int t; scanf("%d", &t); for(int tt = 1; tt <= t; tt++)
#ifndef ONLINE_JUDGE
#define debug(args...) fprintf(stderr,args)
#else
#define debug(args...)
#endif //ONLINE_JUDGE
template<typename T> inline T abs(T t) { return t < 0? -t : t; }
const ll modn = 1000000007;
inline ll mod(ll x) { return x % modn; }
#define IOS() ios::sync_with_stdio(0),cin.tie(0)

const int MAXN = 500005;

int n, m, k;
int s[MAXN];

bool apg[MAXN];

vector<pii> adj[MAXN];
vector<int> comp[MAXN];
int p[MAXN], sz[MAXN];

int raiz(int u){
    if(p[u] == u) return u;
    return p[u] = raiz(p[u]);
}

int join(int u, int v){
    u = raiz(u);
    v = raiz(v);
    if(u == v) return 0;

    if(sz[u] < sz[v])
        swap(u, v);

    sz[u] += sz[v];
    p[v] = u;
    for(int x: comp[v])
        comp[u].pb(x);
    return v;
}
vector<pii> qry;
vector<pii> ares(1);
set<pii> rcomp[MAXN];
int main (){
    int q;
	scanf("%d%d%d", &n, &m, &q);
	for(int a=1;a<=n;a++){
        scanf("%d", s+a);
        p[a] = a;
        sz[a] = 1;
        comp[a].pb(a);
	}
    for(int a=1;a<=m;a++){
        int i, j;
        scanf("%d%d", &i, &j);
        adj[i].pb({j, a});
        adj[j].pb({i, a});
        ares.pb({i, j});
    }
    vector<int> mnRaiz(q);
    vector<vector<int>> mnComp(q);
    for(int a=0;a<q;a++){
        int t, i;
        scanf("%d %d", &t, &i);
        if(t == 2)
            apg[i] = 1;
        qry.pb({t, i});
    }
    for(int a=1;a<=m;a++){
        if(apg[a]) continue;
        int v = join(ares[a].fst, ares[a].snd);
        comp[v].clear();
    }

    for(int a=q-1;a>=0;a--){
        int t,i;
        t = qry[a].fst;
        i = qry[a].snd;
        if(t == 1)
            continue;
        int u = ares[i].fst, v = ares[i].snd;
        mnRaiz[a] = join(u, v);
        if(mnRaiz[a] > 0){
            mnComp[a] = comp[mnRaiz[a]];
            comp[mnRaiz[a]].clear();
        }
    }

    for(int u=1;u<=n;u++){
        if(u == p[u]){
            for(int v: comp[u]){
                rcomp[u].insert({-s[v], v});
            }
        }
    }
    for(int a=0;a<q;a++){
        int t,i;
        t = qry[a].fst;
        i = qry[a].snd;

        if(t == 1){
            int r = raiz(i);
            pii mai = {0, 0};
            if(!rcomp[r].empty()){
                mai = *rcomp[r].begin();
                rcomp[r].erase(rcomp[r].begin());
            }
            printf("%d\n", -mai.fst);
        }
        else{
            if(mnRaiz[a] == 0) continue;
            int mn = mnRaiz[a];
            int oldR = raiz(mn);
            assert(oldR != mn);
            p[mn] = mn;
            for(int v: mnComp[a]){
                p[v] = mn;
                if(rcomp[oldR].find({-s[v], v}) != rcomp[oldR].end()){
                    rcomp[oldR].erase({-s[v], v});
                    rcomp[mn].insert({-s[v], v});
                }
            }
        }
    }
}

#include <bits/stdc++.h>
using namespace std;
#undef LOCAL
#ifdef LOCAL
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string(string(s)); }
string to_string(bool b) { return to_string(int(b)); }
string to_string(char b) { return "'" + string(1, b) + "'"; }
template <typename A, typename B>
string to_string(pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A>
string to_string(A v) {
	string res = "{";
	for (const auto& x : v) res += (res == "{" ? "" : ", ") + to_string(x);
	return res + "}";
}
void debug() { cerr << endl; }
template <typename Head, typename... Tail>
void debug(Head H, Tail... T) {
	cerr << " " << to_string(H);
	debug(T...);
}
#define db(...) cerr << "[" << #__VA_ARGS__ << "]:", debug(__VA_ARGS__)
#else
#define db(...) 42
#endif
typedef long long ll;
typedef long double ld;
vector<int> P;
struct cmp {
	bool operator()(int a, int b) const {
		if (P[a] != P[b]) return P[a] > P[b];
		return a < b;
	};
};
int main() {
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);
	vector<int> A(m), B(m);
	P = vector<int>(n);
	vector<vector<int>> Q(q, vector<int>(2));
	vector<bool> rem(m);
	vector<int> idP(n + 1);
	for (int i = 0; i < n; ++i) {
		scanf("%d", &P[i]);
		idP[P[i]] = i;
	}
	for (int i = 0; i < m; ++i) {
		scanf("%d%d", &A[i], &B[i]);
		--A[i];
		--B[i];
	}
	for (int i = 0; i < q; ++i) {
		scanf("%d%d", &Q[i][0], &Q[i][1]);
		--Q[i][1];
		if (Q[i][0] == 2) {
			rem[Q[i][1]] = true;
		}
	}
	vector<int> par(n);
	iota(par.begin(), par.end(), 0);
	function<int(int)> root = [&](int a) {
		if (par[a] == a) return a;
		return par[a] = root(par[a]);
	};
	vector<vector<int>> S(n + n);
	for (int i = 0; i < n; ++i) S[i] = {i};
	for (int i = 0; i < m; ++i) {
		if (rem[i]) continue;
		int a = root(A[i]), b = root(B[i]);
		if (a == b) continue;
		if (S[a].size() < S[b].size()) swap(a, b);
		par[b] = a;
		S[a].insert(S[a].end(), S[b].begin(), S[b].end());
	}
	vector<int> newComp(q, -1);
	int nex = n;
	for (int i = q - 1; i >= 0; --i) {
		if (Q[i][0] == 2) {
			int e = Q[i][1];
			int a = root(A[e]), b = root(B[e]);
			if (a == b) continue;
			// There is a split of component at query i.
			if (S[a].size() < S[b].size()) swap(a, b);
			swap(S[b], S[nex]);
			sort(S[nex].begin(), S[nex].end(), [&](int x, int y) {
				return P[x] < P[y];
			});
			newComp[i] = nex;
			par[b] = a;
			S[a].insert(S[a].end(), S[nex].begin(), S[nex].end());
			++nex;
		}
	}
	for (int i = 0; i < n; ++i) S[i].clear();
	for (int i = 1; i <= n; ++i) {
		int ii = idP[i];
		root(ii);
		S[par[ii]].push_back(ii);
	}
	for (int i = 0; i < q; ++i) {
		if (Q[i][0] == 1) {
			int r = par[Q[i][1]];
			int val = 0;
			while (!S[r].empty()) {
				int mx = S[r].back();
				S[r].pop_back();
				if (par[mx] != r) continue;
				if (P[mx] == 0) continue;
				val = P[mx];
				P[mx] = 0;
				break;
			}
			printf("%d\n", val);
		} else {
			db(2, i, Q[i][1]);
			if (newComp[i] == -1) continue;
			int r = newComp[i];
			db(r);
			for (int x : S[r]) {
				par[x] = r;
			}
		}
	}
}

#include <bits/stdc++.h>
#define DIMN 800010
using namespace std;
pair <int , int> x[DIMN] , w[DIMN];
int val[DIMN] , tt[DIMN] , f[DIMN] , pp[DIMN] , up[DIMN];
int aint[4 * DIMN] , poz , nn , elem , sol[DIMN];
vector <int> v[DIMN] , qry[DIMN];
int root (int x){
    if (tt[x] < 0)
        return x;
    return (tt[x] = root(tt[x]));
}

void update (int nod , int st , int dr , int poz , int nr){
    int mid = (st + dr) / 2;

    if (st == dr){
        aint[nod] = nr;
        return;
    }

    if (poz <= mid)
        update (2 * nod , st , mid , poz , nr);
    else update (2 * nod + 1 , mid + 1 , dr , poz , nr);

    if (val[aint[2 * nod]] > val[aint[2 * nod + 1]])
        aint[nod] = aint[2 * nod];
    else aint[nod] = aint[2 * nod + 1];

}

int query (int nod , int st , int dr , int l , int r){
    int mid = (st + dr) / 2 , idk = nn + 1 , aux;

    if (l <= st && dr <= r){
        return aint[nod];
    }

    if (l <= mid){
        aux = query (2 * nod , st , mid , l , r);
        if (val[aux] > val[idk])
            idk = aux;
    }

    if (mid + 1 <= r){
        aux = query (2 * nod + 1 , mid + 1 , dr , l , r);
        if (val[aux] > val[idk])
            idk = aux;
    }

    return idk;

}

void dfs (int nod , int tt){
    int i , vecin , nr;

    poz++;
    pp[nod] = poz;

    update (1 , 1 , nn , pp[nod] , nod);

    for (i = 0 ; i < v[nod].size() ; i++){
        vecin = v[nod][i];
        if (vecin != tt)
            dfs (vecin , nod);
    }

    up[nod] = poz;

}

void dfs2 (int nod , int tt){
    int i , vecin , nr;

    for (i = qry[nod].size() - 1 ; i >= 0 ; i--){

        nr = query(1 , 1 , nn , pp[nod] , up[nod]);

        //printf ("%d %d %d\n",nod , elem - qry[nod][i] + 1 , val[nr]);

        sol[elem - qry[nod][i] + 1] = val[nr];

        val[nr] = 0;

        update (1 , 1 , nn , pp[nr] , nr);

    }

    for (i = 0 ; i < v[nod].size() ; i++){
        vecin = v[nod][i];
        if (vecin != tt)
            dfs2 (vecin , nod);
    }

}

int main()
{
    FILE *fin = stdin;
    FILE *fout = stdout;
    int n , m , q , i , rx , ry;
    fscanf (fin,"%d%d%d",&n,&m,&q);
    for (i = 1 ; i <= n ; i++){
        fscanf (fin,"%d",&val[i]);
        tt[i] = -1;
    }

    for (i = 1 ; i <= m ; i++)
        fscanf (fin,"%d%d",&w[i].first,&w[i].second);

    for (i = 1 ; i <= q ; i++){
        fscanf (fin,"%d%d",&x[i].first,&x[i].second);
        if (x[i].first == 2)
            f[x[i].second] = 1;
    }

    for (i = 1 ; i <= m ; i++){

        if (!f[i]){

            rx = root(w[i].first);
            ry = root(w[i].second);

            if (rx != ry){
                if (tt[rx] < tt[ry]){
                    v[rx].push_back(ry);
                    tt[rx] += tt[ry];
                    tt[ry] = rx;
                }
                else {
                    v[ry].push_back(rx);
                    tt[ry] += tt[rx];
                    tt[rx] = ry;
                }
            }

        }

    }

    nn = n;

    for (i = q ; i ; i--){
        if (x[i].first == 2){ /// asta inseamna ca adaugi o muchie practic

            rx = root(w[x[i].second].first);
            ry = root(w[x[i].second].second);

            if (rx != ry){
                nn++;
                v[nn].push_back(rx);
                v[nn].push_back(ry);

                tt[nn] = tt[rx] + tt[ry];
                tt[rx] = nn;
                tt[ry] = nn;
            }

        }
        else {
            elem++;
            qry[root(x[i].second)].push_back(elem);
        }
    }

    for (i = 1 ; i <= nn ; i++){

        if (tt[i] < 0){
            dfs (i , 0);
        }

    }

    for (i = 1 ; i <= nn ; i++){

        if (tt[i] < 0){
            dfs2 (i , 0);
        }

    }

    for (i = 1 ; i <= elem ; i++){
        fprintf (fout,"%d\n",sol[i]);
    }

    return 0;
}

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>

template <typename Tp> void read(Tp &res){
	static char ch; ch = getchar(), res = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) res = res * 10 + ch - 48, ch = getchar();
}

const int MAXN = 2e5 + 19, MAXM = 3e5 + 19, MAXQ = 5e5 + 19;

int n, m, q, fa[MAXN], birth[MAXM], belong[MAXN], p[MAXN], opt[MAXQ], arg[MAXQ];
int getf(int node){return node == fa[node] ? node : fa[node] = getf(fa[node]);}
std::vector<int> mt[MAXN];
std::pair<int, int> G[MAXM];
bool vist[MAXM];

int main(){
	read(n), read(m), read(q);
	for(int i = 1; i <= n; ++i) read(p[i]), fa[i] = i, mt[i].push_back(i);
	for(int i = 1; i <= m; ++i) read(G[i].first), read(G[i].second);
	for(int i = 1; i <= q; ++i){
		read(opt[i]), read(arg[i]);
		if(opt[i] == 2) vist[arg[i]] = 1;
	}
	for(int i = 1; i <= m; ++i){
		if(vist[i]) continue;
		int a = G[i].first, b = G[i].second;
		a = getf(a), b = getf(b);
		if(a == b) continue;
		if(mt[a].size() < mt[b].size()) std::swap(a, b);
		for(int j : mt[b]) mt[a].push_back(j);
		std::vector<int>().swap(mt[b]);
		fa[b] = a;
	}
	for(int i = q; i >= 1; --i)
		if(opt[i] == 2){
			int a = G[arg[i]].first, b = G[arg[i]].second;
			a = getf(a), b = getf(b);
			if(a == b) continue;
			if(mt[a].size() < mt[b].size()) std::swap(a, b);
			birth[arg[i]] = b;
			for(int j : mt[b]) mt[a].push_back(j);
			fa[b] = a;
		}
	for(int i = 1; i <= n; ++i) belong[i] = getf(i), vist[i] = 0;
	for(int i = 1; i <= n; ++i) std::sort(mt[i].begin(), mt[i].end(), [](const int &a, const int &b){return p[a] < p[b];});
	for(int i = 1; i <= q; ++i){
		if(opt[i] == 1){
			int a = belong[arg[i]];
			while(!mt[a].empty() && (belong[mt[a].back()] != a || vist[mt[a].back()])) mt[a].pop_back();
			if(mt[a].empty()) puts("0");
			else printf("%d\n", p[mt[a].back()]), vist[mt[a].back()] = 1;
		}
		else{
			int a = birth[arg[i]];
			if(!a) continue;
			for(int j : mt[a]) belong[j] = a;
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std ;

#define ll int
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define memf(a) memset(a,false,sizeof(a))
#define all(v) v.begin(),v.end()
#define sz(a) (ll)a.size()
#define F first
#define S second
#define INF 2000000000000000000
#define endl "\n"
#define _time_ 1.0 * clock() / CLOCKS_PER_SEC
#define popcount(x) __builtin_popcountll(x)
#define pll pair<ll,ll>
#define ld long double

const int M=1000000007;
const int MM=998244353;
const long double PI = acos(-1);

ll power(ll b,ll e,ll 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);
}
ll power( ll b, ll 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.F<< ","<<p.S<<')';
}

const int N = 200005;
const int LOGN = 19;
int val[N];

struct node
{
    ll mx,idx;
}fake{-N,-1};
    // base value is assigned to fake node
struct SEGTREE
{
    ll a[N];
    SEGTREE(){ mem0(a); }
    node tree[4*N];
    ll 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(ll val,ll st)
    {
        node ret;
        ret.mx=val;
        ret.idx = st;
        return ret;
    }
    void buildTree(ll v,ll st,ll en)
    {
        if(st==en)
        {
            tree[v]=make_node(a[st],st);
            return ;
        }
        ll 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(ll v,ll st,ll en,ll in,ll val)
    {
        ll 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(ll v,ll st,ll en,ll l,ll r)
    {
        if(en<l || st>r)
            return fake;
        if(st>=l && en<=r)
            return tree[v];
        ll 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];
        ll 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,ll 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,ll w)
    {
        u = u-1;
        for(int j=LOGN-1;j>=0;--j)
        {
            // change here
            if(tr[tr[u].p[j]].w>=w)
                u = tr[u].p[j];
        }
        return make_pair(tr[u].l,tr[u].r);
    }
};
// in case of tree call dsu.dfs()
// else call for every component
// 0 based
// number at index i --> pos[i]

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].F>>edges[i].S;
    }
    for(int i=0;i<q;++i)
    {
        int tt,u;
        cin>>tt>>u;
        query.pb({tt,u});
        if(tt==2)
            mark[u-1] = i;
    }
    sort(all(in),[&](int x,int y){
        return mark[x]>mark[y];
    });
    dsu_tree dsu(n);
    for(auto &j:in)
    {
        dsu.merge(edges[j].F,edges[j].S,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].F==2)
            continue;
        pair<int,int> range = dsu.lift(query[i].S,i);
        node u = seg.query(1,0,n-1,range.F,range.S);
        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);
    #ifdef runSieve
        sieve();
    #endif
    #ifdef NCR
        initialize();
    #endif
    int TESTS=1;
    // cin>>TESTS;
    while(TESTS--)
        _runtimeTerror_();
    return 0;
}

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;

int n, m, q;
int p[N];
int wei[N], w[N];
int tim[N], seq[N];
struct edge{
    int l, r;
}e[N];

struct query{
    int l, r, id;
}qq[N];
int tot;
int find(int x)
{
    if(x == p[x]) return x;
    return p[x] = find(p[x]);
}

int cmp(int a, int b)
{
    return tim[a] > tim[b];
}
int ans[N];
vector<int>g[N];

int in[N],out[N], num, pre[N], f[N][21];
int tr[N << 2];

void dfs(int u)
{
    in[u] = ++ num;
    pre[num] = u;
    for (int j = 1; j <= 20; j ++)
        f[u][j] = f[f[u][j - 1]][j - 1];
    for (auto &j : g[u])
    {
        f[j][0] = u;
        dfs(j);
    }
    out[u] = num;
}

void pushup(int rt)
{
    if(w[tr[rt << 1]] >= w[tr[rt << 1 | 1]])
    {
        tr[rt] = tr[rt << 1];
    }
    else
        tr[rt] = tr[rt << 1 | 1];
}

int get(int x, int t)
{
    for (int i = 20; i >= 0; i --)
        if(f[x][i] && wei[f[x][i]] >= t)
            x = f[x][i];
    return x;
}

void build(int rt, int l, int r)
{
    if(l == r)
    {
        tr[rt] = pre[l];
        return ;
    }
    int mid = l + r >> 1;
    build(rt << 1, l, mid);
    build(rt << 1 | 1, mid + 1, r);
    pushup(rt);
}

int query(int rt, int L, int R, int l, int r)
{
    if(L <= l && R >= r)
    {
        return tr[rt];
    }
    int mid = l + r >> 1;
    int res = 0, res1 = 0, res2 = 0;
    if(L <= mid) res1 = query(rt << 1, L, R, l, mid);
    if(R > mid) res2 = query(rt << 1 | 1, L, R, mid + 1, r);
    if(w[res1] >= w[res2])
        res = res1;
    else
        res = res2;
    return res;
}

void update(int rt, int L, int C, int l, int r)
{
    if(l == r)
    {
        w[pre[l]] = C;
        tr[rt] = pre[l];
        return ;
    }
    int mid = l + r >> 1;
    if(L <= mid) update(rt << 1, L, C, l, mid);
    else update(rt << 1 | 1, L, C, mid + 1, r);
    pushup(rt);
}

int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; i ++) scanf("%d", &w[i]), wei[i] = q + 1;
    for (int i = 1; i <= n + n + 10; i ++) p[i] = i;
    for (int i = 1; i <= m; i ++)
    {
        scanf("%d%d", &e[i].l, &e[i].r);
        tim[i] = q + 1;
        seq[i] = i;
    }
    for (int i = 1; i <= q; i ++)
    {
        scanf("%d%d", &qq[i].l, &qq[i].r);
        qq[i].id = i;
        if(qq[i].l == 2)
            tim[qq[i].r] = i;
    }
    sort(seq + 1, seq + m + 1, cmp);
    tot = n;
    for (int i = 1; i <= m; i ++)
    {
        int u = e[seq[i]].l, v = e[seq[i]].r, t = tim[seq[i]];
        int fx = find(u), fy = find(v);
        if(fx == fy) continue;
        wei[++ tot] = t;
        g[tot].push_back(fx); g[tot].push_back(fy);
        p[fx] = tot, p[fy] = tot;
    }
    for (int i = tot; i >= 1; i --)
        if(!in[i])
            dfs(i);
    build(1, 1, num);
    for (int i = 1; i <= q; i ++)
    {
        if(qq[i].l == 1)
        {
            int v = get(qq[i].r, i);
            int tmp = query(1, in[v], out[v], 1, num);
        //   cout << tmp << '\n';
            ans[i] = w[tmp];
            if(ans[i])
                update(1, in[tmp], 0, 1, num);
            printf("%d\n", ans[i]);
        }
    }

}

#include<bits/stdc++.h>

namespace mem{ //v1.8.2 => size: 13.11KiB
  #define MEM_IO
  #define MEM_STR
  #define MEM_MATH
  #define MEM_UTILS
  #define MEM_MODINT
  #define MEM_RANDOM
  #define MEM_STDVAL
  #define MEM_CONTAINER
  #ifdef memset0
  #else
    #define MEM_FASTIO
  #endif

  #ifdef __SIZEOF_INT128__
    #define MEM_INT128
  #endif

  #define __integer_mapper(func)     \
      func(int)                      \
      func(unsigned int)             \
      func(long long)                \
      func(unsigned long long)
  #define __float_mapper(func)       \
      func(float)                    \
      func(double)
  #define __string_mapper(func) \
      func(char *)              \
      func(string &)            \
      func(std::string &)
  #define __string_join_mapper(func)                                              \
      func(vector<string>,string)                                                 \
      func(std::vector<string>,string)                                            \
      template<class T> func(vector<T>,to_string)                                 \
      template<class T> func(std::vector<T>,to_string)

  #ifdef MEM_STDVAL
    namespace stdval{
      using i32=int;
      using i64=long long;
      using u32=unsigned int;
      using u64=unsigned long long;
      using f32=float;
      using f64=double;
  #ifdef MEM_INT128
      using i128=__int128_t;
      using u128=__uint128_t;
  #endif
    }
  #endif

  #ifdef MEM_UTILS
    namespace utils{
      using std::cin;
      using std::tie;
      using std::cout;
      using std::cerr;
      using std::endl;
      using std::swap;
      using std::sort;
      using std::reverse;
      using std::shuffle;
      using std::function;
      using std::make_pair;
      using std::make_tuple;
      using std::lower_bound;
      using std::upper_bound;
      using std::max_element;
      using std::min_element;
    }
  #endif

  #ifdef MEM_IO
    namespace io{
  #ifdef MEM_FASTIO
      namespace fastio{
        const int BUFFER=1<<21;
        char ibuf[BUFFER],*iS,*iT;
        inline int getc(){
          if(iS==iT){
            iT=(iS=ibuf)+fread(ibuf,1,BUFFER,stdin);
            return iS==iT?EOF:*iS++;
          }else{
            return *iS++;
          }
        }
        char obuf[BUFFER],*oS=obuf,*oT=oS+BUFFER-1;
        inline void flush(){
          fwrite(obuf,1,oS-obuf,stdout);
          oS=obuf;
        }
        inline void putc(int x){
          *oS++=x;
          if(oS==oT)flush();
        }
        struct Flusher{~Flusher(){flush();}}flusher;
      }
      using fastio::getc;
      using fastio::putc;
  #else
      inline int getc(){return getchar();}
      inline void putc(int c){putchar(c);}
  #endif

      template<class T> inline void readDigit(T &x){
        x=getc();
        while(!isdigit(x))x=getc();
      }
      inline int readDigit(){
        int x;
        readDigit(x);
        return x;
      }
      template<class T> inline void readAlpha(T &x){
        x=getc();
        while(!isalpha(x))x=getc();
      }
      inline int readAlpha(){
        int x;
        readAlpha(x);
        return x;
      }
      template<class T> inline void readInt(T &x){
        x=0;
        bool f=0;
        char c=getc();
        while(!isdigit(c))f^=c=='-',c=getc();
        while(isdigit(c))x=x*10+c-'0',c=getc();
        if(f)x=-x;
      }

  #define __read(T)                             \
      inline void read(T &x) {                  \
        x=0; bool f=0; char c=getc();           \
        while(!isdigit(c))f^=c=='-',c=getc();   \
        while(isdigit(c))x=x*10+c-'0',c=getc(); \
        if(f)x=-x;                              \
      }
      __integer_mapper(__read)
  #undef __read

      inline void read(char &x){x=getc();}
      template<class T=int> inline T read(){
        T x;
        read(x);
        return x;
      }
      template<class T,class... Args> inline void read(T &x,Args &... args){
        read(x),read(args...);
      }

  #define __print(T)           \
      inline void print(T x){  \
        if(x<0)putc('-'),x=-x; \
        if(x>9)print(x/10);    \
        putc('0'+x%10);        \
      }
      __integer_mapper(__print)
  #undef __print

      inline void print(char x){putc(x);}
      inline void print(const char *s){
        int len=strlen(s);
        for(int i=0;i<len;i++)putc(s[i]);
      }
      inline void print(const std::string &s){
        for(int i=0;i<s.length();i++)putc(s[i]);
      }

      template<class T,class... Args> inline void print(const T &x,Args... args){
        print(x),print(args...);
      }
      template<class... Args> inline void println(Args... args){
        print(args...),putchar('\n');
      }
    }
  #endif

  #ifdef MEM_RANDOM
    namespace random{
      const int LuckyNumber=20040725;
      std::mt19937 rng(LuckyNumber^std::chrono::steady_clock::now().time_since_epoch().count());
      std::mt19937_64 rng64(LuckyNumber^std::chrono::steady_clock::now().time_since_epoch().count());

      template<class T> inline T rand(T l,T r){return std::uniform_int_distribution<T>(l,r)(rng);}
      template<class T> inline T rand64(T l,T r){return std::uniform_int_distribution<T>(l,r)(rng);}
    }
  #endif

  #ifdef MEM_MODINT
    namespace modint{
      template<const int mod> struct Z{
        int x;
        inline Z(){x=0;}
        inline Z(int t){x=t;}

        inline void operator-=(Z a){(x-=a.x)<0&&(x+=mod);}
        inline void operator+=(Z a){(x+=a.x)>=mod&&(x-=mod);}
        inline void operator*=(Z a){x=(long long)x*a.x%mod;}

        friend inline Z operator*(Z a,Z b){return (long long)a.x*b.x%mod;}
        friend inline Z operator-(Z a,Z b){return ((a.x-=b.x)<0&&(a.x+=mod)),a;}
        friend inline Z operator+(Z a,Z b){return ((a.x+=b.x)>=mod&&(a.x-=mod)),a;}
      };

      template<const int mod> inline Z<mod> finv(Z<mod> x){
        if(x.x<2)return x;
        return (mod-mod/x.x)*finv(mod%x.x);
      }
      template<const int mod> inline Z<mod> fpow(Z<mod> a,int b){
        Z <mod> s=1;
        for(;b;b>>=1,a=a*a)
          if(b&1)s=s*a;
        return s;
      }

      template<const int mod> inline void init_inverse(int n,Z<mod> *inv){
        inv[0]=inv[1]=1;
        for(int i=2;i<n;i++)inv[i]=(mod-mod/i)*inv[mod%i];
      }
      template<const int mod> inline void init_factorial(int n,Z<mod> *fac,Z<mod> *ifac){
        fac[0]=1,init_inverse(n,ifac);
        for(int i=1;i<n;i++)fac[i]=fac[i-1]*i,ifac[i]=ifac[i-1]*ifac[i];
      }
    }
  #endif

  #ifdef MEM_MATH
    namespace math{
      using std::max;
      using std::min;
      template<class T> inline T abs(T x){return x<0?-x:x;}
      template<class T> inline T gcd(T n,T m){return m?gcd(m,n%m):n;}
      template<class T> inline T lcm(T n,T m){return n/gcd(n,m)*m;}

      template<const stdval::u64 p> struct FastDiv{
        stdval::u64 t,i;
        inline FastDiv():t(stdval::u64(-1)/p),i(mul_inv(p)){}

        inline bool divide(stdval::u64 n){return n*i<=t;}
        inline bool divide(stdval::i64 n){return stdval::u64(n<0?-n:n)*i<=t;}
        inline stdval::u64 mul_inv(stdval::u64 n){
          stdval::u64 x=n;
          for(int i=0;i<5;++i)x*=2-n*x;
          return x;
        }
      };

  #ifdef MEM_INT128
      template<const stdval::u64 b> struct FastMod{
        stdval::u64 m;
        inline FastMod():m(stdval::u64((stdval::u128(1)<<64)/b)){}

        inline stdval::u64 reduce(stdval::u64 a){
          stdval::u64 q=(stdval::u64)((stdval::u128(m)*a)>>64);
          stdval::u64 r=a-q*b;
          return r>=b?r-b:r;
        }
      };
  #endif
    }
  #endif

  #ifdef MEM_CONTAINER
    namespace container{
      using std::pair;
      using std::tuple;
      using std::set;
      using std::unordered_set;
      using std::map;
      using std::unordered_map;

      template<class T> struct vector:std::vector<T>{
        using std::vector<T>::vector;
        vector():std::vector<T>(){}
        vector(const std::vector<T> &plain):std::vector<T>(plain){}

        inline void read(int s=-1){
          if(~s)this->resize(s);
          for(size_t i=0;i<this->size();i++){
            io::read(this->operator[](i));
          }
        }
        inline void print(char pt0=' ',char pt1='\n'){
          for(size_t i=0;i<this->size();i++){
            io::print(this->operator[](i));
            if(i+1<this->size())io::putc(pt0);
          }
          io::putc(pt1);
        }

        inline void sort(){std::sort(this->begin(),this->end());}
        inline void concat(const vector &rhs){this->insert(this->end(),rhs.begin(),rhs.end());}
        inline bool includes(const T &x) const{return std::find(this->begin(),this->end(),x)!=this->end();}

        inline vector slice(int l,int r) const{
          if(l>r)return {};
          if(r<this->size())return vector(this->begin()+l,this->begin()+r);
          vector<int> rsp=(this->begin()+l,this->end());
          return rsp.resize(r-l),rsp;
        }

        inline void from(const std::set<T> &src){
          this->resize(src.size());
          auto it=this->begin();
          for(const T e:src)*it++=e;
        }

        template<class Function> inline void forEach(Function func){for(const auto &it:*this)func(it);}

        template<class R,class Function> inline vector<R> _map(Function func) const{
          vector <R> res(this->size());
          for(size_t i=0;i<this->size();i++)
            res[i]=func(this->operator[](i));
          return res;
        }
        template<class R> inline vector<R> map(R func(T)) const{return this->_map<R>(func);}
        template<class R> inline vector<R> map(const std::function<R(T)> &func) const{return this->_map<R>(func);}
      };
    }
  #endif

  #ifdef MEM_STR
    namespace str {
      using namespace mem::container;

      struct string:std::string{
        using std::string::string;
        string():std::string(""){}
        string(const std::string &plain):std::string(plain){}

  #define __join_declaration(Vector,_)            \
        inline string join(const Vector &) const;
        __string_join_mapper(__join_declaration)
  #undef __join_declaration

        vector<string> split(const string &delim)const{
          if(this->empty())return {};
          char *src=new char[this->length()+1];
          strcpy(src,this->c_str());
          char *tar=new char[delim.length()+1];
          strcpy(tar,delim.c_str());
          vector<string> rsp;
          for(char *pos=strtok(src,tar);pos;pos=strtok(nullptr,tar))
            rsp.push_back(string(pos));
          delete[] src;
          delete[] tar;
          return rsp;
        }

        template<class... Args> static inline string format(const char *fm,Args... args){
          int len=snprintf(nullptr,0,fm,args...);
          char *buf=new char[len+1];
          snprintf(buf,len+1,fm,args...);
          string str(buf);
          delete[] buf;
          return str;
        }
        template<class... Args> static inline string format(const string &fm,Args... args){
          return format(fm.c_str(),args...);
        }
      };

  #define __to_string(T)                   \
      inline string to_string(const T &x){ \
        return std::to_string(x);          \
      }
      __float_mapper(__to_string)
      __integer_mapper(__to_string)
  #undef __to_string
      template<class T> inline string to_string(const vector<T> &vet){return "{"+string(",").join(vet)+"}";}
      template<class T> inline string to_string(const std::vector<T> &vet){return to_string(vector<T>(vet.begin(),vet.end()));}
      template<const int mod> inline string to_string(const mem::modint::Z<mod> &zval){return std::to_string(zval.x);}

  #define __join_instantiation(Vector,to_string)          \
      inline string string::join(const Vector &vet)const{ \
        if(!vet.size())return "";                         \
        string res=to_string(vet[0]);                     \
        for(size_t i=1;i<vet.size();i++){                 \
          res+=*this;                                     \
          res+=to_string(vet[i]);                         \
        }                                                 \
        return res;                                       \
      }
      __string_join_mapper(__join_instantiation)
  #undef __join_instantiation

      inline void print(const str::string &s){
        for(size_t i=0;i<s.length();i++)mem::io::putc(s[i]);
      }

  #define __printfm(T)                                                      \
      template<class... Args> inline void printfm(const T fm,Args... args){ \
        print(str::string().format(fm,args...));                            \
      }
      __string_mapper(__printfm)
  #undef __printfm
    }
  #endif

  #undef __integer_mapper
  #undef __float_mapper
  #undef __string_mapper
  #undef __string_join_mapper

  #ifdef MEM_IO
    using namespace io;
  #endif
  #ifdef MEM_STR
    using namespace str;
  #endif
  #ifdef MEM_MATH
    using namespace math;
  #endif
  #ifdef MEM_UTILS
    using namespace utils;
  #endif
  #ifdef MEM_MODINT
    using namespace modint;
  #endif
  #ifdef MEM_RANDOM
    using namespace random;
  #endif
  #ifdef MEM_STDVAL
    using namespace stdval;
  #endif
  #ifdef MEM_CONTAINER
    using namespace container;
  #endif
}

const int N=5e5+10;
using namespace mem::io;
using namespace mem::container;

int n,m,q,p[N],anc[N];
bool mrk[N],vis[N];
vector<int> ele[N];
pair<vector<int>,int> dat[N];

struct cmp{
public:
  inline bool operator()(const int x,const int y){
    return p[x]<p[y];
  }
};
std::priority_queue<int,std::vector<int>,cmp> f[N],g[N];

struct Edge{
  int u,v;
}e[N];

struct Query{
  int o,x;
}y[N];

int find(int x){
  if(x==anc[x])return x;
  return find(anc[x]);
}

int pop(int k){
  while(f[k].size()&&g[k].size()){
    if(f[k].top()==g[k].top()){
      f[k].pop(),g[k].pop();
    }else{
      int x=f[k].top();
      f[k].pop();
      return x;
    }
  }
  if(f[k].size()){
    int x=f[k].top();
    f[k].pop();
    return x;
  }else{
    return 0;
  }
}

pair<vector<int>,int> merge(int u,int v){
  u=find(u),v=find(v);
  if(u==v)return {{},-1};
  if(ele[u].size()>ele[v].size())std::swap(u,v);
  ele[v].insert(ele[v].end(),ele[u].begin(),ele[u].end());
  anc[u]=v;
  return {ele[u],u};
}

int main(){
#ifdef memset0
  freopen("1.in","r",stdin);
#endif
  read(n,m,q);
  for(int i=1;i<=n;i++)read(p[i]);
  for(int i=1;i<=m;i++)read(e[i].u),read(e[i].v);
  for(int i=1;i<=q;i++){
    read(y[i].o),read(y[i].x);
    if(y[i].o==2)mrk[y[i].x]=true;
  }
  for(int i=1;i<=n;i++){
    anc[i]=i;
    ele[i].push_back(i);
  }
  for(int i=1;i<=m;i++)
    if(!mrk[i]){
      merge(e[i].u,e[i].v);
    }
  for(int i=q;i>=1;i--){
    if(y[i].o==2){
      dat[i]=merge(e[y[i].x].u,e[y[i].x].v);
    }
    // printf("%d : ",i);
    // for(int i=1;i<=n;i++)printf("%d%c",find(i)," \n"[i==n]);
  }
  for(int i=1;i<=n;i++){
    f[find(i)].push(i);
  }
  for(int i=1;i<=q;i++){
    // printf(">> %d %d\n",y[i].o,y[i].x);
    // printf("%d : ",i);
    // for(int i=1;i<=n;i++)printf("%d%c",find(i)," \n"[i==n]);
    if(y[i].o==1){
      int ans=pop(find(y[i].x));
      vis[ans]=true;
      print(p[ans],'\n');
    }else{
      int src=find(e[y[i].x].u);
      for(int x:dat[i].first){
        anc[x]=dat[i].second;
        if(!vis[x]){
          f[dat[i].second].push(x);
          g[src].push(x);
        }
      }
    }
  }
}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;

struct IO
{
	#define MAXSIZE (1 << 20)
	#define isdigit(x) (x >= '0' && x <= '9')
  	char buf[MAXSIZE],*p1,*p2;
  	char pbuf[MAXSIZE],*pp;
  	IO():p1(buf),p2(buf),pp(pbuf){}
  	inline char gc() {
    	return getchar();
    	if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
    	return p1==p2?' ':*p1++;
  	}
	inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
  	template <class T>
  	inline void read(T &x)
	{
	    register double tmp=1;register bool sign=0; x=0;
	    register char ch=gc();
	    for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
	    for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
	    if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
	    if (sign) x=-x;
  	}
  	inline void read(char *s)
	{
    	register char ch=gc();
		for (;blank(ch);ch=gc());
		for (;!blank(ch);ch=gc()) *s++=ch;
    	*s=0;
  	}
  	inline void read(char &c) {for(c=gc();blank(c);c=gc());}
  	template<class t> inline void write(t x){
		if(x<0) putchar('-'),write(-x);
		else{if(x>9) write(x/10);putchar('0'+x%10);}
	}
} io;

const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;

int n,m,T,a[N],col[N],qx[N],qy[N],fa[N],siz[N];
int ux[N],uy[N],del[N],ok[N];
vector<int> g[N];

struct Node
{
	int op,x,qx;
};
Node q[N];

inline int find(int x) { return fa[x]==x?x:find(fa[x]); }

inline int Query(int x)
{
	while(g[x].size()&&(col[g[x].back()]!=x||ok[g[x].back()])) g[x].pop_back();
	if(!g[x].size()) return 0;
	int ans=g[x].back();
	g[x].pop_back(),ok[ans]=1;
	return ans;
}

signed main()
{
	io.read(n),io.read(m),io.read(T);
	For(i,1,n) io.read(a[i]),g[i].pb(a[i]),fa[i]=i,siz[i]=1;
	For(i,1,m) io.read(ux[i]),io.read(uy[i]);
	For(i,1,T)
	{
		int opt,x;
		io.read(opt),io.read(x);
		q[i]=(Node){opt,x,0};
		if(opt==2) del[x]=1;
	}
	For(i,1,m) if(!del[i])
	{
		int fx=find(ux[i]),fy=find(uy[i]);
		if(fx==fy) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
		fa[fx]=fy,siz[fy]+=siz[fx];
	}
	Dow(i,T,1)
	{
		int op=q[i].op,x=q[i].x;
		int fx=find(ux[x]),fy=find(uy[x]);
		if(fx==fy||op==1) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx],q[i].qx=fx;
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	For(i,1,n) sort(g[i].begin(),g[i].end()),col[a[i]]=find(i);
	For(i,1,T)
	{
		int op=q[i].op,x=q[i].x;
		if(op==1) io.write(Query(find(x))),puts("");
		else if(q[i].qx)
		{
			For(j,0,g[q[i].qx].size()-1) col[g[q[i].qx][j]]=q[i].qx;
			fa[q[i].qx]=q[i].qx;
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

#define N1 500005
#define N2 300005
#define N3 500005
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(x,c,len) lower_bound(c+1,c+len+1,x)-c
#define uppb(x,c,len) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
#define mid (l+r)/2
#define lson l,mid,ls
#define rson mid+1,r,rs
#define root 1,n,0
#define l(x) (x&-x)
#define muti int T;cin>>T;while(T--)
#define G(x) for(int i=head[x];i;i=nxt[i])

int n,m,q,r=1,tmp,op[N3],x[N3],a[N1],w[N1],tim[N2],be[N1],ed[N1],fp[N1];
//vector<int>path[N1];
int tot,head[N1];
int fo[N1],nxt[N1];
int t[N1*4];
int finds(int x){return w[x]==x?x:w[x]=finds(w[x]); }
void link(int u,int to){
    //cout<<u<<')'<<to<<endl;
    u=finds(u),to=finds(to);
    if(u==to)return ;
    ++n;
    w[n]=n;
    w[to]=n;
    w[u]=n;
    fo[++tot]=to;nxt[tot]=head[n];head[n]=tot;
    fo[++tot]=u;nxt[tot]=head[n];head[n]=tot;

}

void dfs(int u){
    //cout<<u<<' '<<endl;
    fp[be[u]=++tmp]=u;
    G(u)dfs(fo[i]);
    ed[u]=tmp;
}
int cma(int x,int y){return a[x]>a[y]?x:y; }
void build(int l,int r,int i){
    t[i]=fp[l];
    if(l==r)return ;
    build(lson);build(rson);
    t[i]=cma(t[ls],t[rs]);
}
void upd(int pos,int l,int r,int i){
    if(l>r)return ;
    t[i]=fp[l];

    if(l==r)return ;
    if(pos<=mid)upd(pos,lson);
    else upd(pos,rson);
    t[i]=cma(t[ls],t[rs]);
}
int quy(int L,int R,int l,int r,int i){
    //cout<<L<<' '<<R<<' '<<l<<' '<<r<<endl;
    if(L>R)return 0;
    if(L<=l&&R>=r)return t[i];
    int res=0;
    if(L<=mid)res=cma(res,quy(L,R,lson));
    if(R>mid)res=cma(res,quy(L,R,rson));
    return res;
}
int main()
{
    cin>>n>>m>>q;
    go(i,1,n)scanf("%d",&a[i]),w[i]=i;w[n+1]=n+1;
    go(i,1,m)scanf("%d%d",&be[i],&ed[i]);
    go(i,1,q){
        scanf("%d%d",&op[i],&x[i]);
        if(op[i]==2)tim[x[i]]=1;
    }
    go(i,1,m)if(!tim[i])link(be[i],ed[i]);
    dep(i,q,1){
        if(op[i]==2)link(be[x[i]],ed[x[i]]);
        if(op[i]==1)x[i]=finds(x[i]);
    }

    go(i,1,n)if(w[i]==i)dfs(i);

    build(root);

    go(i,1,q){
        if(op[i]==2)continue;
        x[i]=quy(be[x[i]],ed[x[i]],root);
        printf("%d\n",a[x[i]]);
        a[x[i]]=0;
        upd(be[x[i]],root);
    }
}

#include "bits/stdc++.h"

using namespace std;

#define _ ios_base::sync_with_stdio(0);cin.tie(0);
#define endl '\n'
#define debug(x) cerr << #x << " == " << (x) << '\n';
#define all(X) (X).begin(), (X).end()
#define sz(X) (int)X.size()

using ll = long long;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3fLL;

int main()
{ _
    int n, m, q; cin >> n >> m >> q;

    static vector p(n, 0);
    for (auto& x : p) cin >> x;

    vector e(m, pair(0, 0));
    for (auto& [u, v] : e)
    {
        cin >> u >> v; --u, --v;
    }

    vector skip(m, 0);
    vector Q(q, pair(0, 0));
    for (auto& [t, x] : Q)
    {
        cin >> t >> x; --x;
        if (t == 2) skip[x] = 1;
    }

    struct Data
    {
        int v;
        bool operator<(const Data& rhs) const
        {
            return pair(p[v], v) > pair(p[rhs.v], rhs.v);
        }
    };

    auto update = [&](set<Data>& S)
    {
        set<Data> R(S.begin(), S.end());
        swap(S, R);
    };

    vector parent(n, 0); iota(all(parent), 0);
    vector S(n, set<Data>());
    for (int u = 0; u < n; ++u)
        S[u].insert(Data{u});

    auto unite = [&](int u, int v)
    {
        while (u != parent[u]) u = parent[u];
        while (v != parent[v]) v = parent[v];
        if (u != v)
        {
            if (sz(S[u]) < sz(S[v])) swap(u, v);
            parent[v] = u;
            for (auto x : S[v]) S[u].insert(x);
            return v;
        }
        return -1;
    };

    for (int j = 0; j < m; ++j)
    {
        if (skip[j]) continue;
        unite(e[j].first, e[j].second);
    }

    vector child(m, -1);
    for (int z = q - 1; z >= 0; --z)
    {
        auto [t, j] = Q[z];
        if (t == 2) child[j] = unite(e[j].first, e[j].second);
    }

    auto split = [&](int j)
    {
        int v = child[j], u = parent[v];
        assert(u == parent[u]);
        for (auto x : S[v]) S[u].erase(x);
        update(S[v]);
        parent[v] = v;
    };

    for (auto [t, x] : Q)
    {
        if (t == 1)
        {
            while(x != parent[x]) x = parent[x];
            int v = S[x].begin()->v;
            cout << p[v] << endl;
            S[x].erase(S[x].begin());
            p[v] = 0;
            S[x].insert(Data{v});
        }
        else if (child[x] != -1) split(x);
    }

    exit(0);
}

#include <iostream>
#include <fstream>
#include <cstdio>

#include <vector>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <stack>

#include <functional>
#include <utility>
#include <algorithm>
#include <cmath>
#include <iterator>
#include <iomanip>

#include <cassert>
#include <random>
#include <chrono>

#include <complex>

using namespace std;

#define ll long long
#define prll pair<ll,ll>
#define m_p make_pair
#define INF (ll)1e18

const ll q = 239017;
const ll mod = 1e9 + 7;
const ll mod2 = 1e9 + 13;
const ll N = 2e5 + 100;
const ll M = 3e5 + 100;
const ll L = 26;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

ll p[N];
prll seg[N];
vector<ll> comp[N];

ll c[N];
prll qrSeg[N+M];
bitset<M> del;

ll get(ll a) {
	if (p[a] == a)
		return a;
	return p[a] = get(p[a]);
}

void merge(ll a, ll b) {
	a = get(a);
	b = get(b);
	if (a == b)return;

	if ((ll)comp[a].size() < (ll)comp[b].size())swap(a, b);

	p[b] = a;
	seg[a].second = seg[b].second;

	for (ll el : comp[b])
		comp[a].push_back(el);
	comp[b].clear();
}

struct SegTree {
	vector<ll> t,id;
	ll n;

	void update(ll v)
	{
		t[v] = max(t[v * 2], t[v * 2 + 1]);

		if (t[v * 2] > t[v * 2 + 1])
			id[v] = id[v * 2];
		else
			id[v] = id[v * 2 + 1];
	}

	void build(ll tl, ll tr, ll v, vector<ll>& a)
	{
		if (tl + 1 == tr)
		{
			t[v] = a[tl];
			id[v] = tl;
			return;
		}

		ll mid = (tl + tr) >> 1;
		build(tl, mid, v * 2, a);
		build(mid, tr, v * 2 + 1, a);

		update(v);
	}

	SegTree(vector<ll>& a)
	{
		if (a.empty())return;

		n = (ll)a.size();
		t.resize(4 * n);
		id.resize(4 * n);

		build(0, n, 1, a);
	}

	void del(ll tl, ll tr, ll v, ll k)
	{
		if (tl > k || tr <= k)return;
		if (tl + 1 == tr && tl == k)
		{
			t[v] = 0;
			return;
		}

		ll mid = (tl + tr) >> 1;
		del(tl, mid, v * 2, k);
		del(mid, tr, v * 2 + 1, k);

		update(v);
	}

	prll get_mx(ll tl, ll tr, ll v, ll l, ll r) {
		if (tr <= l || tl >= r)return { -INF, 1337 };
		if (l <= tl && tr <= r)return { t[v],id[v] };

		ll mid = (tl + tr) >> 1;
		auto a = get_mx(tl, mid, v * 2, l, r);
		auto b = get_mx(mid, tr, v * 2 + 1, l, r);

		return (a.first > b.first ? a : b);
	}

	prll get_mx(ll l, ll r)
	{
		return get_mx(0, n, 1, l, r+1);
	}
};

void $main()
{
	ll n, m, q; cin >> n >> m >> q;

	for (ll i = 0; i < n; ++i)
		cin >> c[i];

	for (ll i = 0; i < n; ++i) {
		p[i] = i;
		seg[i] = { i,i };
		comp[i].push_back(i);
	}

	vector<prll> r;
	for (ll i = 0; i < m; ++i) {
		ll a, b; cin >> a >> b;
		--a; --b;
		r.emplace_back(a, b);
	}

	vector<prll> qr;
	for (ll i = 0; i < q; ++i) {
		ll a, b; cin >> a >> b;
		--b;

		qr.emplace_back(a, b);
		if (a != 1)
			del[b] = 1;
	}

	for (ll i = 0; i < m; ++i)
		if (!del[i])
			qr.emplace_back(2, i);

	reverse(qr.begin(), qr.end());

	ll it = 0;
	for (auto el : qr) {
		if (el.first == 2) {
			merge(r[el.second].first, r[el.second].second);
		}
		else {
			qrSeg[it++] = seg[get(el.second)];
		}
	}

	for (ll i = 0; i < n; ++i)
		merge(0, i);

	//now p = pos
	ll root = get(0);
	for (ll i = 0; i < (ll)comp[root].size(); ++i)
		p[comp[root][i]] = i;

	for (ll i = 0; i < it; ++i)
		qrSeg[i] = { p[qrSeg[i].first],p[qrSeg[i].second] };

	for (ll& el : comp[root])
		el = c[el];

	SegTree tree = SegTree(comp[root]);
	for (ll i = it - 1; i >= 0; --i)
	{
		auto get = tree.get_mx(qrSeg[i].first,qrSeg[i].second);
		cout << get.first << '\n';

		tree.del(0,n,1,get.second);
	}
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
#else
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
#endif
	ios_base::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	$main();

	return 0;
}

#include <bits/stdc++.h>
using namespace std;

/* useful defines with short names */
#define st first
#define nd second
#define pb push_back
#define pp pop_back
#define all(x) (x).begin(), (x).end()
#define lb(a, b, c) lower_bound(a, b, c)
#define ub(a, b, c) upper_bound(a, b, c)
#define forn(i, n) for (int i = 0; i < (n); ++i)
#define ford(i, n) for (int i = (n) - 1; i >= 0; --i)
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define trav(a, x) for (auto& a : x)
#define len(x) (int)(x).size()
#define low(x) ((x) & (-(x))) // lowest bit in number
#define ispow(x) low(x) == (x) // is power of two
#define subm(m, mask) for (int m = ((mask) - 1) & (mask); m; m = (m - 1) & (mask)) // iterate through submasks
#define pct(x) __builtin_popcount(x) // number of set bits in x
#define bits(x) (31 - __builtin_clz(x)) // floor(log2(x))

/* useful typedefs with short names */
typedef long long	ll;
typedef double 	db;
typedef long double ldb;
typedef complex<db> cd;
typedef string      str;

typedef pair<int, int>	pii;
typedef pair<ll, ll>	pll;
typedef pair<db, db>	pdb;
typedef pair<ldb, ldb>	pldb;
typedef pair<int, ll>	pil;
typedef pair<ll, int>	pli;

template<typename T = int>
using vv = vector<T>;

template<typename T1 = int, typename T2 = int>
using umap = unordered_map<T1, T2>;

template<typename T = int>
using uset = unordered_set<T>;

typedef vector<int>		vi;
typedef vector<ll>		vl;
typedef vector<str>      vs;
typedef vector<char>	vc;
typedef vector<bool>     vb;
typedef vector<db>		vdb;
typedef vector<ldb>		vldb;
typedef vector<pii>		vpii;
typedef vector<pll>		vpll;
typedef vector<pdb>		vpdb;
typedef vector<pldb>	vpldb;
typedef vector<pil>		vpil;
typedef vector<pli>		vpli;
typedef vector<vi> 		vvi;
typedef vector<vl>       vvl;

/* pair<T1, T2> operators: +, -, +=, -=, *, *=, -(unary) */
template<typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2>
pair<T1, T2>& operator+=(pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& p);
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2>
pair<T1, T2>& operator-=(pair<T1, T2>& a, const pair<T1, T2>& b);
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(const pair<T1, T2>& p, T3 mult);
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(T3 mult, const pair<T1, T2>& p);

/* modular arithmetic class implementation */
template<int MOD=1'000'000'007>
struct modular
{
    int val;

    modular(ll v = 0) {
        if (v < 0) v = v % MOD + MOD;
        if (v >= MOD) v %= MOD;
        val = int(v);
    }
    modular(uint64_t v) {
        if (v >= MOD) v %= MOD;
        val = int(v);
    }

    modular(int v) : modular(ll(v)) {}
    modular(unsigned v) : modular(uint64_t(v)) {}

    static int inv_mod(int a, int m = MOD) {
        // https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example
        int g = m, r = a, x = 0, y = 1;
        while (r != 0) {
            int q = g / r;
            g %= r; swap(g, r);
            x -= q * y; swap(x, y);
        }
        return x < 0 ? x + m : x;
    }

    explicit operator int() const { return val; }
    explicit operator unsigned() const { return val; }
    explicit operator ll() const { return val; }
    explicit operator uint64_t() const { return val; }
    explicit operator double() const { return val; }
    explicit operator long double() const { return val; }

    modular& operator+=(const modular &other) {
        val -= MOD - other.val;
        if (val < 0) val += MOD;
        return *this;
    }

    modular& operator-=(const modular &other) {
        val -= other.val;
        if (val < 0) val += MOD;
        return *this;
    }

    static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
        return unsigned(x % m);
#endif
        // Optimized mod for Codeforces 32-bit machines.
        // x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int.
        unsigned x_high = unsigned(x >> 32), x_low = unsigned(x);
        unsigned quot, rem;
        asm("divl %4\n"
            : "=a" (quot), "=d" (rem)
            : "d" (x_high), "a" (x_low), "r" (m));
        return rem;
    }

    modular& operator*=(const modular &other) {
        val = fast_mod(uint64_t(val) * other.val);
        return *this;
    }

    modular& operator/=(const modular &other) {
        return *this *= other.inv();
    }

    friend modular operator+(const modular &a, const modular &b) { return modular(a) += b; }
    friend modular operator-(const modular &a, const modular &b) { return modular(a) -= b; }
    friend modular operator*(const modular &a, const modular &b) { return modular(a) *= b; }
    friend modular operator/(const modular &a, const modular &b) { return modular(a) /= b; }

    modular& operator++() {
        val = val == MOD - 1 ? 0 : val + 1;
        return *this;
    }

    modular& operator--() {
        val = val == 0 ? MOD - 1 : val - 1;
        return *this;
    }

    modular operator++(int) { modular before = *this; ++*this; return before; }
    modular operator--(int) { modular before = *this; --*this; return before; }

    modular operator-() const {
        return val == 0 ? 0 : MOD - val;
    }

    friend bool operator==(const modular &a, const modular &b) { return a.val == b.val; }
    friend bool operator!=(const modular &a, const modular &b) { return a.val != b.val; }
    friend bool operator<(const modular &a, const modular &b) { return a.val < b.val; }
    friend bool operator>(const modular &a, const modular &b) { return a.val > b.val; }
    friend bool operator<=(const modular &a, const modular &b) { return a.val <= b.val; }
    friend bool operator>=(const modular &a, const modular &b) { return a.val >= b.val; }

    modular inv() const {
        return inv_mod(val);
    }

    modular pow(int64_t p) const {
        if (p < 0)
            return inv().pow(-p);
        modular a = *this, result = 1;
        while (p > 0) {
            if (p & 1)
                result *= a;
            p >>= 1;
            if (p > 0)
                a *= a;
        }
        return result;
    }

    friend ostream& operator<<(ostream &os, const modular &m) {
        return os << m.val;
    }
};

/* scanf with template */
template<typename T> T scanf_t();

/* scanf template specializations */
template<>  int            scanf_t();
template<>  ll             scanf_t();
template<>  db             scanf_t();
template<>  ldb            scanf_t();
template<>  char           scanf_t();
template<>  float          scanf_t();
template<>  str 	       scanf_t();
str         scanf_t(int);

/* short names for scanf template specializations */
int     (*si)()     =  scanf_t<int>;
ll      (*sl)()     =  scanf_t<ll>;
db      (*sdb)()    =  scanf_t<db>;
ldb     (*sldb)()   =  scanf_t<ldb>;
char    (*sc)()     =  scanf_t<char>;
float   (*sf)()     =  scanf_t<float>;
str 	   (*ss)()     =  scanf_t<str>;

/* printf template functions */
template<typename T> void printf_t(const T&, char='\n', FILE* = stdout);
template<typename T> void printf_t(const T*, char='\n', FILE* = stdout);
template<typename T> void printf_t(T*, char='\n', FILE* = stdout);
template<typename T1, typename T2> void printf_t(const pair<T1, T2>&, char='\n', FILE* = stdout);
template<typename T, typename Alloc, template<typename, typename> class Container>
void printf_t(const Container<T, Alloc>&, char='\n', FILE* = stdout);

/* varadic print that uses printf */
void print();
template<typename T> void _print(char endl, const T&);
template<typename T, typename... Args> void _print(char endl, const T&, const Args&...);
template<typename T> void _print(char endl, T*, T*);
template<typename T> void _print(char endl, T*, int);
template<typename... Args> void print(const Args&...);

/* variadic print without newline at the end */
template<typename... Args> void prt(const Args&...);
template<typename T> void prt(T*, T*);
template<typename T> void prt(T*, int);

/* variadic print to stderr that uses printf */
template<typename T>
void __dbg(const char*, const T&);
template<typename T, typename... Args>
void __dbg(const char*, const T&, const Args&...);
template<typename... Args>
void _dbg(const char*, const Args&...);
template<typename T>
void _dbg(const char*, T*, T*, char='\n', char=' ');
template<typename T>
void _dbg(const char*, T*, int, char='\n', char=' ');

/* when debugging to stderr, grab also names of variables */
#ifdef LOCAL
	#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
#else
	#define dbg(...) 13
#endif

/* read to array from standard input with scanf */
template<typename T> void in(T*, int);
/* read to standard C++ container with scanf and push_back */
template<typename T, typename Alloc, template<typename, typename> class Container>
void sv(Container<T, Alloc>&, int);
template<typename T, typename Alloc>
void sv(vector<T, Alloc>&, int);

/* write an array to standard output */
template<typename It> void out(It, It, char='\n', char=' ', FILE* = stdout);
template<typename It> void out(It, int, char='\n', char=' ', FILE* = stdout);
/* write standard C++ container to standard output */
template<typename Container> void pv(const Container&, char='\n', char=' ', FILE* = stdout);

/* debug functions */
template<typename T>
void print_bits(T x, int=0);

/* useful variables, functions, definitions*/
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define shuffle(a, b) shuffle(a, b, rng)
template<typename T> T rand(T a, T b);
template<typename T> T rand(T n);
template<typename It> It uniq(It begin, It end);
template<typename T> void uniq(vv<T>& v);

/* short names for printf template specializations */
void pi(const int&, char='\n');
void pl(const ll&, char='\n');
void pd(const db&, char='\n');
void pld(const ldb&, char='\n');
void pf(const float&, char='\n');
void pc(const char&, char='\n');
void ps(const str&, char='\n');

/* geometry */
template<typename T1, typename T2>
ll cross(const pair<T1, T2>& p1, const pair<T1, T2>& p2);
template<typename T1, typename T2>
ll dot(const pair<T1, T2>& p1, const pair<T1, T2>& p2);
template<typename T1, typename T2>
ldb vlen(const pair<T1, T2>& v);

/* useful, general purpose algorithms */
ll russian(ll, ll, ll);
ll fastpow(ll, ll, ll);
ll slowpow(ll, ll, ll);
ll extgcd(ll, ll, ll&, ll&);
ll _gcd(ll, ll);
ll _lcm(ll, ll);
ll _inv(ll, ll);

/* useful constants */
const  int  INF   =  1e9;
const  ll   LINF  =  1e18;
const  ll   M     =  1e9 + 7;
// const  ll   M 	   =  998244353LL;
const  ldb  PI    =  acos(-1);
const  ldb  PI_2  =  PI / 2;

typedef modular<M> mod;

struct query {
	int id;
	int type;
	int v;
};

struct seg_tree {
	int p = 1;
	vpii t;
	const pii N = {-INF, -INF};
	seg_tree(int n) {
		while (p < n)
			p <<= 1;
		t.resize(2 * p, N);
	}
	void set_pos(int pos, int val) {
		t[pos + p] = {val, pos};
	}
	void build() {
		for (int i = p - 1; i > 0; --i)
			t[i] = max(t[i + i], t[i + i + 1]);
	}
	pii get_max(int l, int r) {
		l += p; r += p;
		pii res = N;
		while (l < r) {
			if (l & 1)
				res = max(res, t[l++]);
			if (r & 1)
				res = max(res, t[--r]);
			l >>= 1;
			r >>= 1;
		}
		return res;
	}
	void remove(int v) {
		v += p;
		t[v].st = 0;
		v >>= 1;
		while (v) {
			t[v] = max(t[v + v], t[v + v + 1]);
			v >>= 1;
		}
	}
};

template<>
void printf_t(const query& q, char endl, FILE* out) {
	dbg(q.id, q.type, q.v);
	// fprintf(out, "(%d %d %d)%c", q.id, q.type, q.v, endl);
}

const int N = 3e5 + 7;
int p[N], par[N], pos[N];
pii edge[N];
vi verts[N];
bool del[N];

int Find(int a) {
	return a == par[a] ? a : par[a] = Find(par[a]);
}

int Union(int a, int b) {
	if ((a = Find(a)) == (b = Find(b)))
		return -1;
	if (len(verts[a]) > len(verts[b]))
		swap(a, b);
	assert(!verts[a].empty());
	verts[b].insert(verts[b].end(), all(verts[a]));
	par[a] = b;
	return verts[a][0];
}

int main()
{
	int n = si(), m = si(), q = si();
	in(p + 1, n);
	forn (i, m) {
		int u = si(), v = si();
		edge[i] = {u, v};
	}

	vv<query> que;
	forn (i, q) {
		int type = si(), v = si() - 1;
		if (type == 2)
			del[v] = true;
		que.pb({q - i, type, v});
	}
	forn (i, m)
		if (!del[i])
			que.pb({0, 2, i});

	reverse(all(que));

	rep (i, 1, n) {
		par[i] = i;
		verts[i].pb(i);
	}

	vi after(len(que));
	forn (i, len(que)) {
		auto& qq = que[i];
		if (qq.type == 2)
			after[i] = Union(edge[qq.v].st, edge[qq.v].nd);
	}

	dbg(que);
	dbg(after);

	vb done(n + 1);
	set<int> borders = {0};
	seg_tree s(n);
	int cnt = 0;

	rep (i, 1, n) {
		int f = Find(i);
		if (!done[f]) {
			done[f] = true;
			dbg(f, i, verts[f]);
			trav (v, verts[f]) {
				s.set_pos(cnt, p[v]);
				dbg(cnt, p[v]);
				pos[v] = cnt++;
			}
			borders.insert(cnt);
		}
	}

	s.build();

	dbg(borders);
	dbg(pos + 1, n);

	for (int i = len(que) - 1; i >= 0; --i) {
		auto& qq = que[i];
		if (qq.type == 1) {
			int pp = pos[qq.v + 1];
			auto g = borders.upper_bound(pp);
			auto l = next(g, -1);
			pii maxi = s.get_max(*l, *g);
			print(maxi.st);
			dbg(maxi, *l, *g);
			s.remove(maxi.nd);
		}
		else {
			borders.insert(pos[after[i]]);
		}
	}

	return 0;
}

/* scanf template specilizations */
template<> int scanf_t() { int x; scanf("%d", &x); return x; }
template<> db scanf_t() { db x; scanf("%lf", &x); return x; }
template<> ll scanf_t() { ll x; scanf("%lld", &x); return x; }
template<> ldb scanf_t() { ldb x; scanf("%Lf", &x); return x; }
template<> char scanf_t() { char x; scanf(" %c", &x); return x; }
template<> float scanf_t() { float x; scanf("%f", &x); return x; }

/* printf template specilizations */
template<> void printf_t(const int& x, char end, FILE* out) { fprintf(out, "%d%c", x, end); }
template<> void printf_t(const ll& x, char end, FILE* out) { fprintf(out, "%lld%c", x, end); }
template<> void printf_t(const db& x, char end, FILE* out) { fprintf(out, "%.8lf%c", x, end); }
template<> void printf_t(const ldb& x, char end, FILE* out) { fprintf(out, "%.10Lf%c", x, end); }
template<> void printf_t(const float& x, char end, FILE* out) { fprintf(out, "%f%c", x, end); }
template<> void printf_t(const char& x, char end, FILE* out) { fprintf(out, "%c%c", x, end); }
template<> void printf_t(const str& x, char end, FILE* out) { fprintf(out, "%s%c", x.c_str(), end); }
template<> void printf_t(const char* x, char end, FILE* out) { fprintf(out, "%s%c", x, end); }
template<> void printf_t(char* x, char end, FILE* out) { fprintf(out, "%s%c", x, end); }
template<> void printf_t(const mod& x, char end, FILE* out) { printf_t(x.val, end, out); }
template<> void printf_t(const uint64_t& x, char end, FILE* out) { fprintf(out, "%lu%c", x, end); }
template<> void printf_t(const uint32_t& x, char end, FILE* out) { fprintf(out, "%u%c", x, end); }
template<> void printf_t(const bool& x, char end, FILE* out) { fprintf(out, "%d%c", x, end); }
template<> void printf_t(const long& x, char end, FILE* out) { fprintf(out, "%ld%c", x, end); }
template<typename T1, typename T2> void printf_t(const pair<T1, T2>& x, char end, FILE* out) { printf_t(x.st, ' ', out); printf_t(x.nd, end, out); }
template<typename T, typename Alloc, template<typename, typename> class Container>
void printf_t(const Container<T, Alloc>& v, char end, FILE* out) { pv(v, end, ' ', out); }

/* scanf str of unknown length */
template<>
str scanf_t()
{
	int size = 8;
	char* s = (char*)malloc(size * sizeof(char));
	char c;
	while (isspace(c = getchar()));
	*s = c;
	int i = 1;
	while (!isspace(c = getchar()))
	{
		s[i++] = c;
		if (i == size)
			s = (char*)realloc(s, size *= 2);
	}
	s[i] = '\0';
	str res(s);
	free(s);
	return res;
}

/* make print() possible */
void print() { printf("\n"); }

/* variadic print base case */
template<typename T> void _print(char endl, const T& last) { printf_t(last, endl); }

/* variadic print */
template<typename T, typename... Args>
void _print(char endl, const T& first, const Args&... rest)
{
	printf_t(first, ' ');
	_print(endl, rest...);
}

/* print array from begin iterator to end iterator */
template<typename T>
void _print(char endl, T* begin, T* end) { out(begin, end, endl); }

/* print n elements from of array starting from begin iterator */
template<typename T>
void _print(char endl, T* begin, int n) { out(begin, begin + n, endl); }

/* variadic print with newline at the end */
template<typename... Args>
void print(const Args&... args) { _print('\n', args...); }

/* variadic print with no newline at the end */
template<typename... Args>
void prt(const Args&... args) { _print(' ', args...); }

/* analogous to print(T*, T*) */
template<typename T>
void prt(T* begin, T* end) { _print(' ', begin, end); }

/* analogous to print(T*, int) */
template<typename T>
void prt(T* begin, int n) { _print(' ', begin, n); }

/* variadic __dbg base case */
template<typename T>
void __dbg(const char* s, const T& x)
{
	fprintf(stderr, "%s = ", s);
	printf_t(x, ' ', stderr);
}

/* variadic __dbg */
template<typename T, typename... Args>
void __dbg(const char* s, const T& x, const Args&... rest)
{
	int bracket = 0;
	char c;
	while ((c = *s) != ',' || bracket)
	{
		fprintf(stderr, "%c", *s++);
		switch (c)
		{
			case '(':
			case '{':
			case '[':
				++bracket;
				break;
			case ')':
			case '}':
			case ']':
				--bracket;
		}
	}
	fprintf(stderr, " = ");
	printf_t(x, '\0', stderr);
	fprintf(stderr, ",");
	__dbg(s + 1, rest...);
}

/* variadic _dbg - print braces around */
template<typename... Args>
void _dbg(const char* s, const Args&... rest)
{
	fprintf(stderr, "[ ");
	__dbg(s, rest...);
	fprintf(stderr, "]\n");
}

/* _dbg array from begin to end */
template<typename T>
void _dbg(const char* s, T* begin, T* end, char endl, char sep)
{
	fprintf(stderr, "[ ");
	while (*s != ',')
		fprintf(stderr, "%c", *s++);
	fprintf(stderr, " = ");
	out(begin, end, ' ', sep, stderr);
	fprintf(stderr, "]%c", endl);
}

/* _dbg n elements of array starting from begin */
template<typename T>
void _dbg(const char* s, T* begin, int n, char endl, char sep)
{
	_dbg(s, begin, begin + n, endl, sep);
}

/* scanf n variables of type T */
template<typename T>
void in(T* begin, int n)
{
	while (n--)
		*begin++ = scanf_t<T>();
}

/* scanf n variables of type T to standard C++ container and push them back */
template<typename T, typename Alloc, template<typename, typename> class Container>
void sv(Container<T, Alloc>& v, int n)
{
	auto it = std::back_inserter(v);
	while (n--)
		*it = scanf_t<T>();
}

/* little optimization */
template<typename T, typename Alloc>
void sv(vector<T, Alloc>& v, int n)
{
	v.reserve(n);
	auto it = std::back_inserter(v);
	while (n--)
		*it = scanf_t<T>();
}

/* printf array to standard output */
template<typename It>
void out(It begin, It end, char endl, char sep, FILE* outs)
{
	if (begin == end)
	{
		fprintf(outs, "%c", endl);
		return;
	}
	while (next(begin) != end)
		printf_t(*begin++, sep, outs);
	printf_t(*begin, endl, outs);
}

/* printf array to standard output */
template<typename It>
void out(It begin, int n, char endl, char sep, FILE* outs) { out(begin, begin + n, endl, sep, outs); }

/* printf standard C++ container to standard output */
template<typename Container>
void pv(const Container& v, char end, char sep, FILE* outs) { out(all(v), end, sep, outs); }

/* implementation short named functions for template specializations */
void  pi(const   int&     x, char end)  {  printf_t(x, end);  }
void  pl(const   ll&      x, char end)  {  printf_t(x, end);  }
void  pd(const   db&      x, char end)  {  printf_t(x, end);  }
void  pld(const  ldb&     x, char end)  {  printf_t(x, end);  }
void  pf(const   float&   x, char end)  {  printf_t(x, end);  }
void  pc(const   char&    x, char end)  {  printf_t(x, end);  }
void  ps(const   str&  x, char end)     {  printf_t(x, end);  }

/* pair<T1, T2> operators: +, -, +=, -=, *, *=, -(unary) */
template<typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2>& a, const pair<T1, T2>& b) { return { a.st + b.st, a.nd + b.nd }; }
template<typename T1, typename T2>
pair<T1, T2>& operator+=(pair<T1, T2>& a, const pair<T1, T2>& b) { a.st += b.st; a.nd += b.nd; return a; }
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& p) { return { -p.st, -p.nd }; }
template<typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2>& a, const pair<T1, T2>& b) { return { a.st - b.st, a.nd - b.nd }; }
template<typename T1, typename T2>
pair<T1, T2>& operator-=(pair<T1, T2>& a, const pair<T1, T2>& b) { a.st -= b.st; a.nd -= b.nd; return a; }
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(const pair<T1, T2>& p, T3 mult) { return {p.st * mult, p.nd * mult}; }
template<typename T1, typename T2, typename T3>
pair<T1, T2> operator*(T3 mult, const pair<T1, T2>& p) { return {p.st * mult, p.nd * mult}; }

/* geometry functions */
template<typename T1, typename T2>
ll cross(const pair<T1, T2>& p1, const pair<T1, T2>& p2) { return p1.st * p2.nd - p1.nd * p2.st; }
template<typename T1, typename T2>
ll dot(const pair<T1, T2>& p1, const pair<T1, T2>& p2) { return p1.st * p2.st + p1.nd * p2.nd; }
template<typename T1, typename T2>
ldb vlen(const pair<T1, T2>& v) { return sqrtl(dot(v, v)); }

/* russian peasants algorithm */
ll russian(ll a, ll k, ll m)
{
	ll res = 0LL;
	while (k)
	{
		if (k & 1LL)
			res = (res + a) % m;
		a = (a + a) % m;
		k >>= 1;
	}
	return res;
}

/* fast power - a^k % m */
ll fastpow(ll a, ll k, ll m)
{
	ll res = 1LL;
	while (k)
	{
		if (k & 1LL)
			res = (res * a) % m;
		a = (a * a) % m;
		k >>= 1;
	}
	return res;
}

/* fast power with russian peasants algorithm */
ll slowpow(ll a, ll k, ll m)
{
	ll res = 1LL;
	while (k)
	{
		if (k & 1LL)
			res = russian(res, a, m);
		a = russian(a, a, m);
		k >>= 1;
	}
	return res;
}

/* greatest common divisor of a and b */
ll _gcd(ll a, ll b)
{
	while (b)
		swap(a %= b, b);
	return a;
}

/* least common multiple of a and b */
ll _lcm(ll a, ll b)
{
	return a / _gcd(a, b) * b;
}

/* calculate inverse of a modulo */
ll _inv(ll a, ll p)
{
	return fastpow(a, p - 2, p);
}

/* extended Eucilean algorithm implementation - calculate a * k + b * l = GCD(a, b) */
ll extgcd(ll a, ll b, ll& k, ll& l)
{
	if (b == 0)
	{
		k = 1; l = 0;
		return a;
	}
	ll res = extgcd(b, a % b, l, k);
	l -= a / b * k;
	return res;
}

/* print bits of number x */
template<typename T>
void print_bits(T x, int force_len)
{
	assert(0 <= force_len && force_len <= 64);
	static char s[64];
	int i = 63;
	if (force_len)
		while (force_len--)
			s[i--] = '0' + (x & 1),
			x >>= 1;
	else
		while (x)
			s[i--] = '0' + (x & 1),
			x >>= 1;
	printf("%s\n", s + i + 1);
}

/* random number between a and b (integer or float depending on type T) */
template<typename T>
T rand(T a, T b)
{
	using dist = conditional_t<
		is_integral<T>::value,
		uniform_int_distribution<T>,
		uniform_real_distribution<T>
	>;
	return dist(a, b)(rng);
}

/* random number between 0 and n-1 */
template<typename T>
T rand(T n)
{
	static_assert(is_integral<T>::value, "Only integral type supported!");
	return uniform_int_distribution<T>(0, n - 1)(rng);
}

/* "delete" repeated occurences */
template<typename It>
It uniq(It begin, It end)
{
	sort(begin, end);
	return unique(begin, end);
}

/* delete non-unique elements from vector */
template<typename T>
void uniq(vv<T>& v) { v.erase(uniq(all(v)), v.end()); }

#include<cstdio>
#include<algorithm>
struct read{
	static const int bufsize=1<<24;
	char buf[bufsize],*p1,*p2,c,f;
	read():buf(),p1(buf),p2(buf){}
	char gc(){
		return p1==p2&&(p2=buf+fread(p1=buf,1,bufsize,stdin),p1==p2)?EOF:*p1++;
	}
	read& operator >> (int& x){
		for(x=0,c=gc(),f=0;~c&&(c<'0'||c>'9');c=gc())if(c=='-')f=1;
		if(f)for(;c<='9'&&c>='0';c=gc())x=x*10+'0'-c;
		else for(;c<='9'&&c>='0';c=gc())x=x*10-'0'+c;
		return *this;
	}
	read& operator >> (long long& x){
		for(x=0,c=gc(),f=0;~c&&(c<'0'||c>'9');c=gc())if(c=='-')f=1;
		if(f)for(;c<='9'&&c>='0';c=gc())x=x*10+'0'-c;
		else for(;c<='9'&&c>='0';c=gc())x=x*10-'0'+c;
		return *this;
	}
}in;
struct write{
	static const int bufsize=1<<23;
	char buf[bufsize],*p1,*p2,s[50];
	int tp;
	write():p1(buf),p2(buf+bufsize){}
	~write(){flush();}
	void flush(void){
		fwrite(buf,1,p1-buf,stdout),p1=buf;
	}
	void pc(const char& c){
		if(p1==p2)flush();
		*p1++=c;
	}
	write& operator <<(int x){
		if(x<0)x=-x,pc('-');
		do{s[tp++]=x%10+'0',x/=10;}while(x);
		while(tp)pc(s[--tp]);
		return *this;
	}
	write& operator <<(const char& x){
		pc(x);
		return *this;
	}
}out;
int n,m,q,a[200010];
struct edge{
	int u,v,t;
	bool operator <(edge const &x)const{
		return t<x.t;
	}
}p[300010];
struct ask{
	int op,u,l,r;
}t[500010];
int f[200010],cnt,hd[200010],ed[200010],pre[200010],nxt[200010];
int find(int x){
	while(x!=f[x])x=f[x]=f[f[x]];
	return x;
}
int dfn[200010],rk[200010];
struct node{
	int v,p;
}tr[800010];
void pushup(int const &x,int const &ls,int const &rs){
	if(tr[ls].v>tr[rs].v) tr[x]=tr[ls];
	else tr[x]=tr[rs];
}
void build(int const &x=1,int const &l=1,int const &r=n){
	if(l==r) return tr[x].v=a[rk[l]],tr[x].p=l,void();
	int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
	build(ls,l,mid),build(rs,mid+1,r);
	pushup(x,ls,rs);
}
node query(int const &pl,int const &pr,int const &x=1,int const &l=1,int const &r=n){
	if(l==pl&&r==pr) return tr[x];
	int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
	if(pr<=mid) return query(pl,pr,ls,l,mid);
	else if(pl>mid) return query(pl,pr,rs,mid+1,r);
	else{
		node ll=query(pl,mid,ls,l,mid),rl=query(mid+1,pr,rs,mid+1,r);
		return ll.v>rl.v?ll:rl;
	}
}
void update(int const &p,int const &x=1,int const &l=1,int const &r=n){
	if(l==r) return tr[x].v=0,void();
	int mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
	if(p<=mid) update(p,ls,l,mid);
	else update(p,rs,mid+1,r);
	pushup(x,ls,rs);
}
int main(){
    in>>n>>m>>q;
	for(int i=1;i<=n;i++)in>>a[i],f[i]=i,hd[i]=ed[i]=i;
	for(int i=1;i<=m;i++)in>>p[i].u>>p[i].v,p[i].t=q+1;
	for(int i=1;i<=q;i++)in>>t[i].op>>t[i].u;
	for(int i=1;i<=q;i++)if(t[i].op==2)p[t[i].u].t=i;
	std::sort(p+1,p+m+1);
	int tmp=q;
	for(int i=m;i;i--){
		for(;tmp>=p[i].t;--tmp){
			if(t[tmp].op==2) continue;
			int x=find(t[tmp].u);
			t[tmp].l=hd[x],t[tmp].r=ed[x];
		}
		int x=find(p[i].u),y=find(p[i].v);
		if(x==y) continue;
		nxt[ed[x]]=hd[y];
		pre[hd[y]]=ed[x];
		f[x]=y,hd[y]=hd[x];
	}
	for(;tmp;--tmp){
		if(t[tmp].op==2) continue;
		int x=find(t[tmp].u);
		t[tmp].l=hd[x],t[tmp].r=ed[x];
	}
	for(int i=1;i<=n;i++)
		if(!pre[i])
			for(int k=i;k;k=nxt[k])
				rk[dfn[k]=++cnt]=k;
	build();
	for(int i=1;i<=q;i++){
		if(t[i].op==2) continue;
		node w=query(dfn[t[i].l],dfn[t[i].r]);
		out<<w.v<<'\n';
		update(w.p);
	}
	return 0;
}

#include <bits/stdc++.h>
//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
#define sz(x) int(x.size())
#define all(x) x.begin(),x.end()
#define PB push_back
#define MP make_pair
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pil pair<int, ll>
#define pli pair<ll, int>
#define pdd pair<ld, ld>
#define ft first
#define sd second
#define i2 array<int,2>
#define i3 array<int,3>
#define l2 array<ll,2>
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
template<class T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
const int N = 200100;
const int BIG_N = 400100;
const int M = 300100;
const int Q = 500100;
const int BIG = int(5e8) + 10;
const int oo = 2e9;
const ll OO = 1e18;
const int md = 998244353;
const int PW = 30;
const ld E = 1e-9;
const int MX = (1 << 20);
vector<int> g[BIG_N];
int n, p[BIG_N], U[M], V[M], pre[BIG_N], a[BIG_N];
int m, q, tp[Q], vl[Q], lst, tin[BIG_N], tout[BIG_N], tt = 0, mem_ver[Q];
i2 st[4 * BIG_N];
bool mrk[M], used[BIG_N];

mt19937 rnd(chrono::system_clock().now().time_since_epoch().count());

void BAD(){
    cout << -1;
    exit(0);
}

int get(int x) { return (pre[x] == x ? x : pre[x] = get(pre[x])); }

void dfs(int v){
    a[tt] = p[v];
    tin[v] = tt++;

    for (int u : g[v])
        dfs(u);

    tout[v] = tt - 1;
}

void build(int v, int l, int r){
    if (l == r){
        st[v] = {a[l], l};
        return;
    }

    int md = (l + r) >> 1;

    build(v + v, l, md);
    build(v + v + 1, md + 1, r);

    st[v] = max(st[v + v], st[v + v + 1]);
}

i2 get(int v, int tl, int tr, int l, int r){
    if (l > r) return {-oo, 0};

    if (tl == l && tr == r) return st[v];

    int md = (tl + tr) >> 1;

    return max(get(v + v, tl, md, l, min(r, md)),
               get(v + v + 1, md + 1, tr, max(md + 1, l), r));
}

void update(int v, int l, int r, int ps){
    if (l == r){
        st[v] = {0, l};
        return;
    }

    int md = (l + r) >> 1;

    if (ps <= md)
        update(v + v, l, md, ps);
    else update(v + v + 1, md + 1, r, ps);

    st[v] = max(st[v + v], st[v + v + 1]);
}

int main() {
#ifdef _LOCAL
    freopen("in.txt","r",stdin); // freopen("output.txt","w",stdout);
#else
//    freopen("mining.in","r",stdin); freopen("mining.out","w",stdout);
    ios_base::sync_with_stdio(0); cin.tie(0);
#endif

    cin >> n >> m >> q;

    for (int i = 1; i <= n; i++)
        cin >> p[i];

    for (int i = 1; i <= m; i++){
        cin >> U[i] >> V[i];
    }

    for (int i = 1; i <= q; i++){
        cin >> tp[i] >> vl[i];

        if (tp[i] == 2)
            mrk[vl[i]] = 1;
    }

    for (int i = 1; i < BIG_N; i++){
        pre[i] = i;
    }

    lst = n;

    for (int i = 1; i <= m; i++)
        if (!mrk[i]){
            int xx = get(U[i]), yy = get(V[i]);

            if (xx == yy) continue;

            lst++;

            g[lst].PB(xx);
            g[lst].PB(yy);

            pre[xx] = lst;
            pre[yy] = lst;
        }

    for (int it = q; it > 0; it--){
        if (tp[it] == 1){
            mem_ver[it] = get(vl[it]);
            continue;
        }

        mrk[vl[it]] = 0;

        int i = vl[it];

        int xx = get(U[i]), yy = get(V[i]);

        if (xx == yy) continue;

        lst++;

        g[lst].PB(xx);
        g[lst].PB(yy);

        pre[xx] = lst;
        pre[yy] = lst;
    }

    lst++;

    for (int i = 1; i <= n; i++){
        if (used[get(i)]) continue;

        used[get(i)] = 1;

        g[lst].PB(get(i));
    }

    dfs(lst);

    build(1, 0, lst - 1);

    for (int it = 1; it <= q; it++)
        if (tp[it] == 1){
            int v = mem_ver[it];

            i2 res = get(1, 0, lst - 1, tin[v], tout[v]);

            cout << res[0] << '\n';

            update(1, 0, lst - 1, res[1]);
        }

    return 0;
}

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<tuple>
#include<cassert>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define Per(i,sta,n) for(int i=n-1;i>=sta;i--)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
template<class T>bool chmax(T &a, const T &b) {if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T &a, const T &b) {if(b<a){a=b;return 1;}return 0;}

template <class S, S (*op)(S, S), S (*e)()> struct SegmentTree {
  public:
    SegmentTree() : SegmentTree(0) {}
    SegmentTree(int n) : SegmentTree(std::vector<S>(n, e())) {}
    SegmentTree(const std::vector<S>& v) : _n(int(v.size())) {
        log = ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set_val(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S query(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_query() { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) {//f(op([l,r)))==trueを満たす最大のr
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) {//f(op([l,r)))==trueを満たす最小のl
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }

    int ceil_pow2(int n) {
        int x = 0;
        while ((1U << x) < (unsigned int)(n)) x++;
        return x;
    }
};

struct UnionFind {
private:
    vector<int> par,ran;
    vector<int> edge,size;
    int n;
public:
    UnionFind(int x){
      n=x;
      par.resize(n,0);
      ran.resize(n,0);
      edge.resize(n,0);
      size.resize(n,1);
      rep(i,n){
        par[i]=i;
      }
    }
    int find(int x) {
        if (par[x]==x)return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x, int y) {
        x=find(x),y=find(y);
        if (x==y){
            edge[x]++;
            return;
        }
        if (ran[x]<ran[y]) {
            par[x]=y;
            size[y]+=size[x];
            edge[y]+=edge[x]+1;
        }
        else {
            par[y]=x;
            size[x]+=size[y];
            edge[x]+=edge[y]+1;
            if (ran[x]==ran[y])ran[x]++;
        }
    }
    bool same(int x,int y) {
        return find(x)==find(y);
    }
    int getSize(int x){
        return size[find(x)];
    }
    int getEdge(int x){
        return edge[find(x)];
    }
};

struct T{
  int idx,h;
  T(int h,int idx):h(h),idx(idx){}
  T(){}
};

T F(T a,T b){
  if(a.h>=b.h) return a;
  return b;
}

T e1(){return T(0,0);}

int n,m,q;
int a[200010];
P e[300010],qs[500010];
vector<int> G[600010];
vector<int> S[500010];
vector<bool> is_root;
P sec[600010];
int p[300010],inv[300010];

void dfs(int s,int &id){
  sec[s].first=id+1;
  if(G[s].empty()) {
    id++;
    p[id]=s;
    inv[s]=id;
  }
  for(int t:G[s]){
    dfs(t,id);
  }
  sec[s].second=id+1;
}

void solve(){
  scanf("%d%d%d",&n,&m,&q);
  rep(i,n) scanf("%d",&a[i]);
  rep(i,m){
    scanf("%d%d",&e[i].first,&e[i].second);
    e[i].first--;e[i].second--;
  }
  vector<P> units={};
  vector<bool> used(m,false);
  rep(i,q){
    scanf("%d%d",&qs[i].first,&qs[i].second);
    qs[i].second--;
    if(qs[i].first==2) {
      units.push_back(P(i,qs[i].second));
      used[qs[i].second]=true;
    }
  }
  rep(i,m){
    if(!used[i]) units.push_back(P(q,i));
  }
  int U=n;
  UnionFind uf(n);is_root.resize(n,true);
  vector<int> nodes(n);rep(i,n) nodes[i]=i;
  per(i,units.size()){
    P u=units[i];
    int v1=uf.find(e[u.second].first),v2=uf.find(e[u.second].second);
    //cout << i << " " << e[u.second].first << " " << e[u.second].second << endl;
    if(uf.same(v1,v2)) continue;
    G[U].push_back(nodes[v1]);
    G[U].push_back(nodes[v2]);
    is_root[nodes[v1]]=false;
    is_root[nodes[v2]]=false;
    is_root.push_back(true);
    uf.unite(v1,v2);
    nodes[uf.find(v1)]=U;
    S[u.first].push_back(U);
    U++;
  }
  int id=-1;
  set<P> se;
  rep(i,U){
    if(!is_root[i]) continue;
    dfs(i,id);
    se.insert(P(sec[i].first,sec[i].second));
  }
  vector<T> vec(n);
  rep(i,n) vec[i]=T(a[p[i]],i);
  SegmentTree<T,F,e1> seg(vec);
  //rep(i,U) cout << sec[i].first << " " << sec[i].second << endl;
  rep(i,q){
    for(int z:S[i]){
      int t1=G[z][0],t2=G[z][1];
      se.erase(sec[z]);
      se.insert(sec[t1]);
      se.insert(sec[t2]);
    }
    if(qs[i].first==1){
      //cout << inv[qs[i].second] << endl;
      auto it=se.lower_bound(P(inv[qs[i].second],mod));it--;
      P p=(*it);
      //cout << p.first << " " << p.second << endl;
      T t=seg.query(p.first,p.second);
      printf("%d\n",t.h);
      seg.set_val(t.idx,T(0,t.idx));
    }
  }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(50);
    solve();
}

#include <bits/stdc++.h>
using namespace std;

int parent[200005], sizex[200005];
int deletedEdge[300005], smallParent[500005];
pair<int, int> edge[300005];

set<int, greater<int> > S[200005];
vector<int> P[200005], X[500005];
vector< pair<int, int> > query;

int find_parent(int x)
{
    if (x == parent[x])
        return x;

    return parent[x] = find_parent(parent[x]);
}

void unite(int a, int b, int indx)
{
    a = find_parent(a);
    b = find_parent(b);

    if (a == b)
        return;

    if (sizex[a] > sizex[b])
        swap(a, b);

    parent[a] = b;
    sizex[b] += sizex[a];

    for (auto p : P[a])
    {
        P[b].push_back(p);

        if (indx != -1)
            X[indx].push_back(p);
    }

    if (indx != -1)
        smallParent[indx] = a;

    P[a].clear();
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL), cout.tie(NULL);

    int n, m, q;
    cin >> n >> m >> q;

    for (int i=1; i<=n; i++)
    {
        int p;
        cin >> p;
        P[i].push_back(p);
        parent[i] = i, sizex[i] = 1;
    }

    for (int i=1; i<=m; i++)
        cin >> edge[i].first >> edge[i].second;

    for (int i=0; i<q; i++)
    {
        int type, x;
        cin >> type >> x;

        query.push_back({type, x});

        if (type == 2)
            deletedEdge[x] = 1;
    }

    for (int i=1; i<=m; i++)
        if (!deletedEdge[i])
            unite(edge[i].first, edge[i].second, -1);

    for (int i=q-1; i>=0; i--)
    {
        if (query[i].first == 1)
            continue;

        int indx = query[i].second;
        int x = edge[indx].first, y = edge[indx].second;

        unite(x, y, i);
    }

    for (int i=1; i<=n; i++)
    {
        parent[i] = find_parent(i);

        for (auto p : P[i])
            S[i].insert(p);
    }

    for (int i=0; i<q; i++)
    {
        if (query[i].first == 1)
        {
            int root = parent[ query[i].second ];

            if (root == 0 || S[root].empty())
                cout << 0 << "\n";
            else
            {
                cout << *S[root].begin() << "\n";
                S[root].erase(S[root].begin());
            }
            continue;
        }

        if (X[i].empty())
            continue;

        int originalParent = parent[ X[i].back() ];
        int newParent = smallParent[i];

        for (auto x : X[i])
        {
            if (S[ originalParent ].find(x) == S[ originalParent ].end())
            {
                parent[x] = 0;
                continue;
            }

            parent[x] = newParent;
            S[ newParent ].insert(x);
            S[ originalParent ].erase(x);
        }
    }

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500005;
const int maxm=500005;
const int maxq=500005;
const int inf=0x3f3f3f3f;
int n,m,Q,a[maxn],fa[maxn],x_[maxm],y_[maxm],u_[maxq],v_[maxq]; bool vis[maxm];
set<int> s[maxn];
set<int>::iterator it,itl,itr;
struct oper { int op,u; } q[maxq];
inline int find(int x) { return (x==fa[x])?x:fa[x]=find(fa[x]); }
/*
struct union_set
{
	int col[maxn],fa[maxn],cnt[maxn],x_[maxn],y_[maxn],tot;
	inline void init()
	{
		tot=0;
		for(int i=1;i<=n;i++) fa[i]=i,cnt[i]=1;
	}
	inline int find(int x) { while(x!=fa[x]) x=fa[x]; return x; }
	inline bool merge(int x,int y)
	{
		int u=find(x),v=find(y);
		tot++,x_[tot]=y_[tot]=-1;
		if(u==v) return false;
		if(cnt[u]>cnt[v]) swap(u,v);
		x_[tot]=u,y_[tot]=v;
		fa[u]=v,cnt[v]+=cnt[u];
		return true;
	}
	inline void cancel()
	{
		if(x_[tot]==-1) { tot--; return; }
		fa[x_[tot]]=x_[tot];
		cnt[y_[tot]]-=x_[tot];
		tot--;
	}
	inline void cover(int x,int y) { col[find(x)]=y; }
}s;
void solve(int l,int r,int ql,int qr)
{
	if(l>r || ql>qr) continue;

}
*/
int main()
{
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d%d",&x_[i],&y_[i]);
	for(int i=1;i<=Q;i++)
	{
		scanf("%d%d",&q[i].op,&q[i].u);
		if(q[i].op==2) vis[q[i].u]=1;
	}
	/*
	s.init();
	for(int i=1;i<=m;i++)
		if(!vis[i]) s.merge(x_[i],y_[i]);
	for(int i=1;i<=n;i++) id[i]=i;
	solve(1,Q,1,n);
	*/
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++)
		if(!vis[i])
		{
			int u=find(x_[i]),v=find(y_[i]);
			if(u!=v) fa[u]=v;
		}
	for(int i=1;i<=n;i++) s[find(i)].insert(a[i]);
	for(int i=Q;i;i--)
		if(q[i].op==2)
		{
			int u=find(x_[q[i].u]),v=find(y_[q[i].u]);
			if(u==v) continue;
			if(s[u].size()>s[v].size()) swap(u,v);
			u_[i]=u,v_[i]=v,fa[u]=v;
			for(it=s[u].begin();it!=s[u].end();it++)
				s[v].insert(*it);
		}
	static int sta[maxn],top;
	for(int i=1;i<=Q;i++)
		if(q[i].op==1)
		{
			int u=find(q[i].u);
			if(s[u].empty()) { puts("0"); continue; }
			printf("%d\n",*s[u].rbegin());
			s[u].erase(*s[u].rbegin());
		}
		else if(q[i].op==2)
		{
			if(!u_[i]) continue;
			int u=u_[i],v=v_[i]; fa[u]=u,top=0;
			for(it=s[u].begin();it!=s[u].end();it++)
			{
				itr=s[v].find(*it);
				if(itr==s[v].end()) sta[++top]=*it;
				else s[v].erase(itr);
			}
			for(;top;top--) s[u].erase(s[u].find(sta[top]));
		}
	return 0;
}

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <memory.h>

using namespace std;

int val[200005];
pair<int, int> e[300005];
bool del[300005];
int qT[500005], qV[500005];

int color[200005];

inline int repr(int x) {
  return color[x] == x ? x : (color[x] = repr(color[x]));
}

vector<int> f[200005];
pair<pair<int, int>, int> op[500005];

inline void join(int x, int y, int ind) {
  x = repr(x); y = repr(y);

  if (x != y) {
    if (f[x].size() < f[y].size())  swap(x, y);
    f[x].insert(f[x].end(), f[y].begin(), f[y].end());
    color[y] = x;

    if (ind != -1) {
      op[ind] = {{x, y}, y};
    }
  }
}

int root[200005];
set<pair<int, int>> ff[200005];

int main() {
  ios::sync_with_stdio(false);
  int n, m, q;
  cin >> n >> m >> q;
  for (int i = 0; i < n; ++i) cin >> val[i];
  for (int i = 0; i < m; ++i) {
    cin >> e[i].first >> e[i].second;
    e[i].first--; e[i].second--;
  }
  for (int i = 0; i < q; ++i) {
    cin >> qT[i] >> qV[i], qV[i]--;
    if (qT[i] == 2) del[qV[i]] = true;
  }

  for (int i = 0; i < n; ++i) {
    color[i] = i;
    f[i].push_back(i);
  }

  for (int i = 0; i < m; ++i) {
    if (del[i]) continue;
    join(e[i].first, e[i].second, -1);
  }

  for (int i = q - 1; i >= 0; --i) {
    if (qT[i] == 2) {
      join(e[qV[i]].first, e[qV[i]].second, i);
    }
  }

  for (int i = 0; i < n; ++i) {
    ff[repr(i)].insert({-val[i], i});
    root[i] = repr(i);
    // cout << i << "  " << repr(i) << endl;
  }

  for (int i = 0; i < q; ++i) {
    if (qT[i] == 1) {
      if (ff[root[qV[i]]].size() > 0) {
        set<pair<int, int>>::iterator it = ff[root[qV[i]]].begin();
        cout << -it->first << endl;
        val[it->second] = 0;
        ff[root[qV[i]]].erase(it);
      } else {
        cout << 0 << endl;
      }
    } else {
      for (int t : f[op[i].second]) {
        root[t] = op[i].first.second;
        if (val[t] > 0) {
          ff[op[i].first.first].erase({-val[t], t});
          ff[op[i].first.second].insert({-val[t], t});
        }
      }
    }
  }

  return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int, int>
#define ull unsigned ll
#define f first
#define s second
#define ALL(x) x.begin(),x.end()
#define SZ(x) (int)x.size()
#define SQ(x) (x)*(x)
#define MN(a,b) a = min(a,(__typeof__(a))(b))
#define MX(a,b) a = max(a,(__typeof__(a))(b))
#define pb push_back
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#ifdef BALBIT
#define IOS()
#define bug(...) fprintf(stderr,"#%d (%s) = ",__LINE__,#__VA_ARGS__),_do(__VA_ARGS__);
template<typename T> void _do(T &&x){cerr<<x<<endl;}
template<typename T, typename ...S> void _do(T &&x, S &&...y){cerr<<x<<", ";_do(y...);}
#else
#define IOS() ios_base::sync_with_stdio(0);cin.tie(0);
#define endl '\n'
#define bug(...)
#endif

const int iinf = 1e9+10;
const ll inf = 1ll<<60;
const ll mod = 1e9+7 ;

void GG(){cout<<"0\n"; exit(0);}

ll mpow(ll a, ll n, ll mo = mod){ // a^n % mod
    ll re=1;
    while (n>0){
        if (n&1) re = re*a %mo;
        a = a*a %mo;
        n>>=1;
    }
    return re;
}

ll inv (ll b, ll mo = mod){
    if (b==1) return b;
    return (mo-mo/b) * inv(mo%b,mo) % mo;
}

const int maxn = 2e5+5;
const int maxm = 3e5+5;
vector<pii> g[maxn]; // to, index
//int par[maxn];
int dt[maxm]; // when this edge dies
int val[maxn];
bool dead[maxn];

//int find(int a) {
//    return a==par[a]?a:par[a] = find(par[a]);
//}

int n,m,q;
vector<int> pq[maxn];

const int BS = 300;

int col[maxn];
void dcol(int v, int c, int TT) {
    col[v] = c;
    if (!dead[val[v]])
        pq[c].pb(val[v]);
    for (pii &u : g[v]) {
        if (dt[u.s] > TT && col[u.f] == 0) {
            dcol(u.f,c,TT);
        }
    }
}

int A[maxn], B[maxn];
vector<pii> G[maxn];

int bg = 0, frm = -1;
bool seen[maxn];
vector<int> touch;
void dfs(int v, int TT) {
    seen[v] = 1;
//    touch.pb(v);
    if (SZ(pq[v]) && pq[v].back() > bg) {
        bg = pq[v].back();
        frm = v;
    }
    for (pii &u : G[v]) {
        if (dt[u.s] > TT &&!seen[u.f]) {
            dfs(u.f, TT);
        }
    }
}

signed main(){
    IOS();

    cin>>n>>m>>q;
    memset(dt, 0x3f, sizeof dt);
    for (int i = 0; i<n; ++i) {
        cin>>val[i];
    }
    for (int i = 0; i<m; ++i) {
        int a,b; cin>>a>>b; --a; --b;
        g[a].pb({b,i});
        g[b].pb({a,i});
        A[i] = a; B[i] = b;
    }
    int NOWT = 0;
    vector<pii> vt; // vertex, time
    vector<int> dat;
    for (int cnt = 0; cnt<q; ++cnt) {
        int tp; cin>>tp;
        if (tp == 1) {
            int v; cin>>v;
            vt.pb({v-1,NOWT});
        }else{
            NOWT++;
            int e; cin>>e;
            --e;
            dat.pb(e);
            dt[e] = NOWT; // only available for ppl < NOWT
        }
        bool added = 0;
        if (cnt == q-1 && tp != 2) ++NOWT, added = 1;
        if ((tp == 2 && NOWT % BS == 0) || cnt == q-1) {
            bug(cnt, "START");
            if (SZ(vt) == 0) continue;
            // gogogogo
            int NCOL = 1;
            memset(col, 0, sizeof col);

            for (int i = 0; i<n; ++i){
                if (col[i] == 0) {
                    pq[NCOL].clear();
                    dcol(i, NCOL ++, NOWT-1);
                }
            }

            bug(NCOL);

            for (int i = 1; i<NCOL; ++i) {
                sort(ALL(pq[i]));
            }

                bug(SZ(pq[0]));
            vector<int> hv;
            set<pii> sen;
            for (int i = vt[0].s; i<NOWT-added; ++i) {
                if (sen.count({col[A[dat[i]]], col[B[dat[i]]]})) continue;
                G[col[A[dat[i]]]].pb({col[B[dat[i]]],dat[i]});
                G[col[B[dat[i]]]].pb({col[A[dat[i]]],dat[i]});
                hv.pb(col[A[dat[i]]]);
                hv.pb(col[B[dat[i]]]);
                sen.insert({col[A[dat[i]]], col[B[dat[i]]]});
            }
            SORT_UNIQUE(hv);
//            continue;
            for (pii & p : vt) {
                bug(p.f, col[p.f]);
                bg=0; frm = -1;
                dfs(col[p.f], p.s);
                cout<<bg<<endl;
                if (bg != 0) {
                    pq[frm].pop_back(); dead[bg] = 1;
                }
                for (int &x : hv) seen[x] = 0;
//                touch.clear();
            }
            for(int y : hv) G[y].clear();
            vt.clear();
        }
    }

}

#include <bits/stdc++.h>

using namespace std;

int n, m, q, p[200011];

struct Edge {
	int u, v;
} e[300011];

struct oper {
	int opt, s, sma;
	bool tree;
} ques[500011];

bool del[300011];

namespace Sets {
	int fa[200011], siz[200011];
	int find(int w) {
		if(w == fa[w]) return w;
		return fa[w] = find(fa[w]);
	}
	void merge(int x, int y) {
		int fx = find(x), fy = find(y);
		siz[fy] += siz[fx]; fa[fx] = fy;
	}
}

namespace Graph {
	struct edge {
		int u, v, nxt;
		bool flag;
	} a[600011];
	int tot, fir[200011];
	void addedge(int from, int to) {
		a[++tot].u = from;
		a[tot].v = to;
		a[tot].nxt = fir[from];
		a[tot].flag = 1;
		fir[from] = tot;
	}
	void deledge(int w) {
		a[w*2].flag = 0;
		a[w*2+1].flag = 0;
	}
	vector <pair<int, int> > b[200011];
	int cnt, belong[200011], siz[200011], End[200011];
	void dfs1(int w) {
		belong[w] = cnt; siz[cnt]++; End[cnt] = siz[cnt];
		b[cnt].push_back(make_pair(p[w], w));
		int now = fir[w];
		while(now) {
			if(!belong[a[now].v]) dfs1(a[now].v);
			now = a[now].nxt;
		}
	}
	void dfs2(int w) {
		belong[w] = cnt; siz[cnt]++; End[cnt] = siz[cnt];
		b[cnt].push_back(make_pair(p[w], w));
		int now = fir[w];
		while(now) {
			if(a[now].flag == 1 && belong[a[now].v] != cnt)
				dfs2(a[now].v);
			now = a[now].nxt;
		}
	}
	int query(int w) {
		while(End[w] > 0 && belong[b[w][End[w]-1].second] != w) End[w]--;
		if(End[w] < 1) return 0;
		int ret = b[w][End[w]-1].first;
		p[b[w][End[w]-1].second] = 0;
		End[w]--;
		return ret;
	}
}

void print() {
	for(int i = 1; i <= Graph::cnt; i++) {
		cout << i << ":" << endl;
		for(int j = 0; j < Graph::siz[i]; j++) {
			cout << Graph::b[i][j].second << " " << Graph::b[i][j].first << endl;
		}
	}
	cout << "belongs:";
	for(int i = 1; i <= n; i++)
	cout << Graph::belong[i] << " "; cout << endl;
}

int main() {
	scanf("%d%d%d", &n, &m, &q);
	Graph::tot = 1; Graph::cnt = 0;
	memset(Graph::belong, 0, sizeof(Graph::belong));
	memset(Graph::fir, 0, sizeof(Graph::fir));
	for(int i = 1; i <= n; i++)
		scanf("%d", &p[i]), Sets::fa[i] = i;
	for(int i = 1; i <= m; i++) {
		scanf("%d%d", &e[i].u, &e[i].v);
		Graph::addedge(e[i].u, e[i].v);
		Graph::addedge(e[i].v, e[i].u);
	}
	for(int i = 1; i <= q; i++) {
		scanf("%d%d", &ques[i].opt, &ques[i].s);
		if(ques[i].opt == 2) del[ques[i].s] = 1;
	}
	for(int i = 1; i <= m; i++)
		if(!del[i]) Sets::merge(e[i].u, e[i].v);
	for(int i = q; i >= 1; i--) {
		if(ques[i].opt == 2) {
			int x = e[ques[i].s].u, y = e[ques[i].s].v;
			if(Sets::find(x) == Sets::find(y)) ques[i].tree = 0;
			else {
				ques[i].tree = 1;
				if(Sets::siz[x] < Sets::siz[y]) ques[i].sma = x;
				else ques[i].sma = y;
				Sets::merge(x, y);
			}
		}
	}
	for(int i = 1; i <= n; i++) {
		if(!Graph::belong[i]) {
			Graph::cnt++;
			Graph::dfs1(i);
		}
	}
	//for(int i = 1; i <= n; i++)
	//	cout << Graph::belong[i] << " "; cout << endl;
	for(int i = 1; i <= Graph::cnt; i++)
		sort(Graph::b[i].begin(), Graph::b[i].end());
	/*for(int i = 1; i <= Graph::cnt; i++) {
		cout << i << ":" << endl;
		for(int j = 0; j < Graph::siz[i]; j++) {
			cout << Graph::b[i][j].second << " " << Graph::b[i][j].first << endl;
		}
	}*/
	//return 0;
	for(int i = 1; i <= q; i++) {
		if(ques[i].opt == 1) {
			int bel = Graph::belong[ques[i].s];
			printf("%d\n", Graph::query(bel));
		}
		else {
			//continue;
			//cout << e[ques[i].s].u << "--" << e[ques[i].s].v << endl;
			Graph::deledge(ques[i].s);
			if(ques[i].tree == 0) continue;
			int x = e[ques[i].s].u, y = e[ques[i].s].v;
			//cout << "tree edge" << endl;
			Graph::cnt++;
			Graph::dfs2(ques[i].sma);
			//print();
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifndef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
	*this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<long long, int> pli;
typedef long long ll;
#define f first
#define s second
#define endl '\n'
#define all(x) x.begin(),x.end()
const int N=5e5+1;
int p[ N ],tin [ N ],tout[ N ],timer;
int get( int v ){
    return p[v] = ( v == p[v] ? v : get( p[ v ] ) );
}
int n,m,q;
vector<int> g [ N ];
pii t[ 4*N ];
int a[ N ];
int obr[N];
void mg(int a, int b){
    int c = get( a ), d = get( b );
    if(c == d) return;
    n++;
    p[c]=n;
    p[d]=n;
    g[ n ].emplace_back(c);
    g[ n ].emplace_back(d);
    return ;
}
void dfs(int v, int p){
    tin[ v ] = timer++;
    obr[ timer - 1 ] = v;
    for(auto &z : g[ v ]){
//        if(z == p) continue;
        dfs( z, v );
    }
    tout[ v ] = timer - 1;
}
void b_tr(int v,int tl,int tr){
    if(tl == tr){
        t[v]={a[obr[tl]],tl};
    }
    else{
        int tm=(tl+tr)>>1;
        b_tr(2*v,tl,tm);
        b_tr(2*v+1,tm+1,tr);
        t[v]=max(t[2*v],t[2*v+1]);
    }
}
pii getMax(int l,int r,int v,int tl,int tr){
    if(tl>=l && tr<=r){
        return t[v];
    }
    if(tl>r || tr<l) return {0,n};
    int tm=(tl+tr)>>1;
    return max(getMax(l,r,2*v,tl,tm),getMax(l,r,2*v+1,tm+1,tr));
}
void upd(int id,int v,int tl,int tr){
    if(tl==tr){
        t[v].first=0;
        return ;
    }
    int tm=(tl+tr)>>1;
    if(tm>=id)
        upd(id,2*v,tl,tm);
    else
        upd(id,2*v+1,tm+1,tr);
    t[v]=max(t[2*v],t[2*v+1]);
}
pii e[N];
bool ex[N];
pii qe[N];
signed main(){
    cin.tie(0);cout.tie(0);ios_base::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0;i < m;i++){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    iota(p,p+N,0);
    for(int i = 0;i < q;i++){
        int tp;
        cin>>tp;
        int id;
        cin>>id;
        if(tp==2){
            ex[id-1]=1;
        }
        qe[i]={tp,id};
    }
    for(int i = 0; i < m;i++){
        if(!ex[i]){
            mg(e[i].f,e[i].s);
//            for(int i = 1;i <= n; i++){
////                debug()<<imie(get(i));
//            }
//            cout<<endl;
        }
    }
    for(int i = q - 1; ~ i; --i){
        if(e[i].f==2)
            mg(e[qe[i].s-1].f,e[qe[i].s-1].s);
        else {

//            debug()<<imie(qe[i].s)imie(get(qe[i].s));
            qe[i].s=get(qe[i].s);
        }
    }
    for(int i = 1;i <= n; i++){
        if(get(i)==i)
            dfs(i,i);
    }
    b_tr(1,1,n);
//    for(int i = 1;i <= n; i++){
//        debug()<<imie(tin[i])imie(tout[i])imie(getMax(tin[i],tin[i],1,1,n))imie(a[i]);
//    }
//    vector<int> ans;
    for(int i = i=0; i<q; i++){
        if(qe[i].f==1){
            int id=qe[i].s;
            auto w=getMax(tin[id],tout[id],1,1,n);
            upd(w.s,1,1,n);
//            debug()<<imie(w)imie(id);
            cout<<w.f<<endl;
        }
    }
//    reverse(all(ans));
//    for(auto &z : ans) cout<<z<<endl;
    return 0;
}

#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;

const int N = 200005;
const int M = 300005;
const int Q = 500005;

int n, m, q, ori;
int ea[M], eb[M], er[N];
int type[Q], qu[Q];
int c[N+N];
int dup[N+N][20];
int par[N+N];

vector<int> g[N+N];
int in[N+N], out[N+N], dfs_t;

void dfs(int u) {
	if(u <= ori) {
		in[u] = ++dfs_t;
		out[u] = dfs_t;
		return;
	}
	in[u] = -1;
	for(int v : g[u]) {
		dfs(v);
		if(in[u] == -1) in[u] = in[v];
	}
	out[u] = dfs_t;
}

int f(int u) {
	return u == par[u] ? u : par[u] = f(par[u]);
}

int get_root(int u, int ti) {

	for(int j = 19; j >= 0; j--) {
		if(c[ dup[u][j] ] >= ti) {
			u = dup[u][j];
		}
	}
	return u;
}

pair<int, int> st[4*N];

void upd(int i, int val, int p, int L, int R) {
	if(i < L or i > R) return;
	if(L == R) {
		st[p] = {val, L};
		return;
	}
	int mid = (L + R) / 2;
	upd(i, val, 2 * p, L, mid);
	upd(i, val, 2 * p + 1, mid + 1, R);
	st[p] = max(st[2 * p], st[2 * p + 1]);
}
pair<int, int> query(int i, int j, int p, int L, int R) {
	if(j < L or i > R) return {-1, -1};
	if(L >= i and R <= j) return st[p];
	int mid = (L + R) / 2;
	return max(query(i, j, 2 * p, L, mid), query(i, j, 2 * p + 1, mid + 1, R));
}
int p[N];

int main() {
	scanf("%d %d %d", &n, &m, &q);
	ori = n;

	for(int i = 1; i <= n; i++) scanf("%d", p + i);

	for(int i = 1; i <= m; i++) {
		scanf("%d %d", ea + i, eb + i);
	}

	for(int i = 0; i < q; i++) {
		scanf("%d %d", type + i, qu + i);
		if(type[i] == 2) er[ qu[i] ] = 1;
	}

	for(int i = 1; i <= n; i++) par[i] = i, c[i] = q;

	for(int i = 1; i <= m; i++) if(!er[i]) {
		int a = f(ea[i]), b = f(eb[i]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = q;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = q - 1; i >= 0; i--) if(type[i] == 2) {
		int a = f(ea[ qu[i] ]), b = f(eb[ qu[i] ]);
		if(a == b) continue;
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = i;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	for(int i = 2; i <= ori; i++) if(f(i) != f(1)) {
		int a = f(1), b = f(i);
		++n;
		dup[a][0] = dup[b][0] = n;
		par[a] = par[b] = par[n] = n;
		c[n] = -1;
		g[n].push_back(a);
		g[n].push_back(b);
	}

	dup[n][0] = n;

	for(int lvl = 0; lvl + 1 < 20; lvl++) {
		for(int i = 1; i <= n; i++) {
			dup[i][lvl + 1] = dup[ dup[i][lvl] ][lvl];
		}
	}

	dfs(n);

	for(int i = 1; i <= ori; i++) {
		upd(in[i], p[i], 1, 1, ori);
	}

	for(int i = 0; i < q; i++) {
		if(type[i] == 1) {
			int r = get_root(qu[i], i);
			auto [val, id] = query(in[r], out[r], 1, 1, ori);
			printf("%d\n", val);
			upd(id, 0, 1, 1, ori);
		}
	}
}

// Expected verdict: Wrong Answer
// But this does surprisingly well against random test cases,
// and may pass if systests are weak, even though it is rubbish

#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
#include <algorithm>

using VI = std::vector<int>;

struct ST {
  VI& src;
  VI arr;
  int p2;

  int imax(int i, int j) {
    return (src[i] == src[j] ? i > j : src[i] > src[j]) ? i : j;
  }

  void update(int L, int R) {
    L = (L + p2) >> 1;
    R = (R + p2 + 1) >> 1;
    while (L) {
      for (int i = L; i < R; ++i)
        arr[i] = imax(arr[2*i], arr[2*i+1]);
      L = L >> 1;
      R = (R + 1) >> 1;
    }
    return;
  }

  void update(int ix) {
    ix = (ix + p2) >> 1;
    while (ix) {
      arr[ix] = imax(arr[2*ix], arr[2*ix+1]);
      ix >>= 1;
    }
    return;
  }

  ST(VI& _src)
    :src { _src }
  {
    int n = int(src.size());
    assert(n % 2 == 0);
    for (p2 = 1; p2 < n; p2 <<= 1)
      ;
    arr = VI(n + p2, n-1);
    for (int i = 0; i < n; ++i)
      arr[i + p2] = i;
    update(0, n);
  }

  int rmq(int L, int R) {
    int ans = L;
    L += p2;
    R += p2;
    while (L < R) {
      ans = imax(ans, arr[L]);
      ans = imax(ans, arr[R-1]);
      L = (L + 1) >> 1;
      R >>= 1;
    }
    return ans;
  }
};

int main() {
  using namespace std;
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, m, q;
  cin >> n >> m >> q;
  VI p = VI(n+1);
  for (int i = 1; i <= n; ++i)
    cin >> p[i];

  struct UE { // Undirected Edge
    int priority;
    int u;
    int v;
  };

  vector<UE> edges = vector<UE>(m+1);
  for (int i = 1; i <= m; ++i) {
    int u, v;
    cin >> u >> v;
    edges[i].priority = q + i;
    edges[i].u = p[u];
    edges[i].v = p[v];
  }

  struct Query {
    int priority;
    int v;
  };
  vector<Query> queries;
  queries.reserve(q);
  for (int i = 1; i <= q; ++i) {
    int t, v;
    cin >> t >> v;
    if (t == 1)
      queries.push_back(Query { i, v });
    else
      edges[v].priority = i;
  }

  struct E { // Edge
    int priority;
    int oSide;

    bool operator < (E o) const {
      return priority < o.priority;
    }
  };

  vector<vector<E>> gr = vector<vector<E>>(n+1);
  for (UE e : edges) {
    gr[e.u].push_back(E { e.priority, e.v });
    gr[e.v].push_back(E { e.priority, e.u });
  }
  for (Query cq : queries)
    gr[cq.v].push_back(E { cq.priority, -1 });

  struct QueryInterval {
    int priority;
    int start;
    int stop;
  };
  vector<int> vertexLabels;
  vertexLabels.reserve(n + n % 2);
  vector<QueryInterval> qis;
  qis.reserve(queries.size());

  { // calculate vertexLabels, qis
    priority_queue<E> pq;
    for (int i = 1; i <= n; ++i)
      pq.push(E { 0, i });
    vector<char> vis = vector<char>(n+1, char(false));

    struct PStackObj {
      int priority;
      int start;
    };
    vector<PStackObj> stack;

    while (!pq.empty()) {
      E e = pq.top();
      pq.pop();
      while (!stack.empty() && stack.back().priority >= e.priority)
        stack.pop_back();
      if (e.oSide == -1) { // vertex query
        assert(!stack.empty());
        qis.push_back(QueryInterval {
            e.priority, stack.back().start, int(vertexLabels.size()) });
      }
      else { // real edge: follow
        if (vis[e.oSide])
          continue;
        vis[e.oSide] = char(true);
        stack.push_back(PStackObj { e.priority, int(vertexLabels.size()) });
        vertexLabels.push_back(e.oSide);
        for (E e2 : gr[e.oSide])
          pq.push(e2);
      }
    }
    assert(int(vertexLabels.size()) == n);
    if (n % 2)
      vertexLabels.push_back(vertexLabels.back());
  }

  ST st { vertexLabels };
  sort(qis.begin(), qis.end(), [](QueryInterval qi1, QueryInterval qi2) {
      return qi1.priority < qi2.priority;
    });
  for (QueryInterval cqi : qis) {
    int i = st.rmq(cqi.start, cqi.stop);
    assert(0 <= i);
    assert(i < n);
    cout << vertexLabels[i] << endl;
    vertexLabels[i] = 0;
    st.update(i);
  }

  return 0;
}

#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization ("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(auto i = (a); i < (b); i++)
#define pb push_back
#define fs first
#define sc second
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ii> vii;
typedef vector<vii> vvii;

const double EPS = 1e-9;

typedef pair<int,ii> T;

set<ii> BST[200'050];
struct union_find {
	vi p;
    vi sz;
    vi A;

    vector<unordered_set<int>> BACK;

	union_find(int n, vi &b) : A(b), p(n), sz(n,1), BACK(n,unordered_set<int>()) {
        rep(i,0,n) p[i] = i;
        rep(i,0,n) BST[i].insert(ii(A[i],i));
    }

    stack<T> q;
    int cur = 0;

	int find(int a) {
        if(a == p[a]) return a;
        return find(p[a]);
    }

    int best(int a) {
        a = find(a);
        if(BST[a].size() == 0) return 0;
        ii val = *(--BST[a].end());
        BST[a].erase(val);
        A[val.sc] = 0;
        return val.fs;
    }

	bool joined(int a, int b) {
        return find(a) == find(b);
    }

    void change(int at, int from, int to) {
        if(A[at] != 0) {
            BST[from].erase(ii(A[at],at));
            BST[to].insert(ii(A[at],at));
        }
        for(auto a : BACK[at]) {
            change(a, from, to);
        }
    }

    void change_forward(int from, int to) {
        for(auto a : BST[from]) {
            BST[to].insert(a);
        }
    }

	void unite(int a, int b) {

        a = find(a);
        b = find(b);
        if(a == b) {
            q.push(T(-1,ii(0,0)));
            return;

        }

        if(sz[a] < sz[b]) {
            // go through smaller size remove and add to other
            change_forward(a, b);

            sz[b] += sz[a];

            q.push( T(cur, ii(a, p[a])) );
            BACK[b].insert(a);

            p[a] = b;

        } else {
            change_forward(b, a);

            sz[a] += sz[b];
            q.push( T(cur, ii(b, p[b])) );

            BACK[a].insert(b);

            p[b] = a;

        }
    }

    void pop() {
        T a = q.top();
        q.pop();
        if(a.fs == -1) return;
        int top = find(a.sc.fs);
        change(a.sc.fs, top, a.sc.fs);
        BACK[top].erase(a.sc.fs);
        sz[top] -= sz[a.sc.fs];
        p[a.sc.fs] = a.sc.sc;
    }
};

int main() {
    cin.sync_with_stdio(false);
    int n,m,q;
    cin >> n >> m >> q;

    vi A(n);
    rep(i,0,n) cin >> A[i];
    vii E;
    rep(i,0,m) {
        int u,v;
        cin >> u >> v;
        u--;v--;
        E.pb(ii(u,v));
    }
    union_find un(n, A);

    vii OP(q);
    rep(i,0,q) cin >> OP[i].fs >> OP[i].sc;
    vi IS_REM(m,0);
    for(int i = q-1; i >= 0; i--) {
        if(OP[i].fs == 2) {
            IS_REM[OP[i].sc-1] = 1;
        }
    }
    rep(i,0,m) {
        if(!IS_REM[i]) {
            un.unite(E[i].fs, E[i].sc);
        }
    }
    for(int i = q-1; i >= 0; i--) {
        if(OP[i].fs == 2) {
            un.unite(E[OP[i].sc-1].sc, E[OP[i].sc-1].fs);
        }
    }
    for(int i = 0; i < q; i++) {
        if(OP[i].fs == 1) {
            int val = un.best(OP[i].sc-1);
            cout << val << endl;
        } else {
            un.pop();
        }
    }
}

#include<bits/stdc++.h>
using namespace std;
#define I inline int
#define V inline void
#define ll long long int
#define isnum(ch) ('0'<=ch&&ch<='9')
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define REP(u) for(int i=h[u],v;v=e[i].t,i;i=e[i].n)
#define gc (_op==_ed&&(_ed=(_op=_buf)+fread(_buf,1,100000,stdin),_op==_ed)?EOF:*_op++)
char _buf[100000],*_op(_buf),*_ed(_buf);
I getint(){
	int _s=0,_f=1;char _ch=gc;
	while(!isnum(_ch))(_ch=='-')&&(_f=-1),_ch=gc;
	while(isnum(_ch))_s=_s*10+_ch-48,_ch=gc;
	return _s*_f;
}
const int N=3e5+2,INF=0x3f3f3f3f;
set<int>mp[N];
int T,n,m,q,ans;
int w[N],a[N],b[N],id[N];
int fa[N],siz[N],tag[N];
int opt[N],val[N],dis[N][2];
vector<int>cha[N],now[N];
V input(){
	n=getint(),m=getint(),q=getint();
	FOR(i,1,n)w[i]=getint(),id[w[i]]=i;
	FOR(i,1,m)a[i]=getint(),b[i]=getint(),tag[i]=1;
	FOR(i,1,q)opt[i]=getint(),val[i]=getint();
}
V merge(int x,int y){
	if((x=fa[x])==(y=fa[y]))return;
	if(siz[x]<siz[y])swap(x,y);
	for(int v:now[y])now[x].push_back(v),fa[v]=x;
	siz[x]+=siz[y];
}
V init(int x=0,int y=0){
	FOR(i,1,n)fa[i]=i,siz[i]=1,now[i].push_back(i);
	FOR(i,1,q)if(opt[i]==2)tag[val[i]]=0;
	FOR(i,1,m)if(tag[i])merge(a[i],b[i]);
	ROF(i,q,1)if(opt[i]==2){
		x=a[val[i]],y=b[val[i]];
		if((x=fa[x])==(y=fa[y]))continue;
		if(siz[x]<siz[y])swap(x,y);
		for(int v:now[y])now[x].push_back(y),fa[v]=x;
		fa[y]=x,siz[x]+=siz[y],dis[i][0]=x,dis[i][1]=y;
	}
	FOR(i,1,n)mp[fa[i]].insert(w[i]);
}
V work(){
	int x,y,p;
	FOR(i,1,q)
		if(opt[i]==1){
			x=fa[val[i]];
			p=*--mp[x].end();
			cout<<p<<'\n';
			w[id[p]]=0;
			mp[x].erase(p);
			mp[x].insert(0);
		}
		else if(dis[i][0]){
			x=dis[i][0],y=dis[i][1];
			FOR(j,1,siz[y])
				now[x].pop_back();
			siz[x]-=siz[y];
			for(int v:now[y]){
				fa[v]=y,mp[y].insert(w[v]);
				if(mp[x].find(w[v])!=mp[x].end())mp[x].erase(w[v]);
			}
			mp[x].insert(0);
		}
}
int main(){
//	freopen("test.in","r",stdin);
//	freopen(".out","w",stdout);
//	for(scanf("%d",&T);T--;){
		input();
		init();
		work();
//	}
	return 0;
}

#include <bits/stdc++.h>
//#include "race.h"
//    #pragma GCC optimize("-O3")
//    #pragma GCC optimize("no-stack-protector")
//    #pragma GCC optimize("fast-math")
//    #pragma GCC optimize("Ofast")
//    #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx")
//    #pragma GCC target("avx,avx2,fma")
//    #pragma GCC optimization ("unroll-loops")
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fi first
#define f first
#define s second
#define se second
#define vec vector
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define pb push_back
#define sz(x) (int)x.size()
#define pw(x) (1ll<<x)
#define p_b push_back
#define m_p make_pair
#define fast_io ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define sq(x) (x)*(x)
//#define int long long
using namespace std;
using namespace __gnu_pbds;
typedef pair<long long, long long> PII;
typedef pair<int, int> pii;
typedef long double ld;
typedef long long ll;
typedef pair<long long, long long > pll;
template <typename T> umax(T &a, T b){return (a<b ? a=b,1 : 0);}
template <typename T> umin(T &a, T b){return (a>b ? a=b,1 : 0);}
typedef tree<pii,null_type,less<pii>,rb_tree_tag,tree_order_statistics_node_update> o_set;
const int N=2e5+5;
const ll inf=1e9;
const ld eps = 1e-9;
const int ppp=73;
const int M=99999837;
const ll tx[4]={-1,1,0,0};
const ll ty[4]={0,0,-1,1};
const char rev_to[4]={'U','D','L','R'};
auto rnd=bind(uniform_int_distribution<ll>(1,1e9),mt19937(time(0)));
int n,m,q;
int p[N],in[N],out[N],obr[N],t;
vec<int> g[N];
void make(int v){
    p[v]=v;
}
int get(int v){
    return p[v]=(p[v]==v?v:get(p[v]));
}
void mg(int a,int b){
    int c=get(a),d=get(b);
    if(c==d){
        return;
    }
    p[c]=++n;
    p[d]=n;
    g[n].pb(c);
    g[n].pb(d);
}
struct seg{
    pii t[4*N];
    void init(){
        fill(t,t+4*N,m_p(0,0));
    }
    void upd(int v,int tl,int tr,int id, pii vl){
        if(tl==tr){
            t[v]=vl;
            return;
        }
        int tm=(tl+tr)>>1;
        if(tm>=id)
            upd(2*v,tl,tm,id,vl);
        else
            upd(2*v+1,tm+1,tr,id,vl);
        t[v]=max(t[2*v],t[2*v+1]);
    }
    pii get(int l,int r,int v,int tl,int tr){
        if(tl>=l && tr<=r){
            return t[v];
        }
        if(tl>r || tr<l){
            return {0,0};
        }
        int tm=(tl+tr)>>1;
        return max(get(l,r,2*v,tl,tm),
                   get(l,r,2*v+1,tm+1,tr));
    }
}Do;
int a[N];
pii e[N];
bool used[N];
void dfs(int v){
    in[v]=++t;
    obr[t]=v;
    for(auto &z : g[v]){
        if(!in[z])
            dfs(z);
    }
    out[v]=t;
}
signed main()
{
    fast_io;
//    ifstream cin("numpalindrome.in");
//    ofstream cout("numpalindrome.out");
    cin>>n>>m>>q;
    for(int i = 1; i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0 ; i < m; ++i){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    vec<pii>zapr(q);
    for(int i = 0; i < q; ++i){
        cin>>zapr[i].f>>zapr[i].s;
        if(zapr[i].f==1){

        }
        else{
            zapr[i].s--;
            used[zapr[i].s]=1;
        }
    }
    for(int i = 1; i < N; ++i)
        make(i);
    for(int i = q - 1 ; ~i; --i){
        if(zapr[i].f==1){
            int x=get(zapr[i].s);
            zapr[i].s=x;
        }
        else{
            mg(e[zapr[i].s].f,e[zapr[i].s].s);
        }
    }
    for(int i = 1; i <= n; i ++){
        if(get(i)==i){
            dfs(i);
        }
    }
    for(int i = 1; i <= n; i++){
        Do.upd(1,1,n,in[i],{a[i],in[i]});
    }
    for(int i = 0; i < q; i++){
        if(zapr[i].f==1){
            int x=zapr[i].s;
            pii c=Do.get(in[x],out[x],1,1,n);
            Do.upd(1,1,n,c.s,{0,c.s});
            cout<<c.f<<"\n";
        }
    }
    return 0;
}
/*
(3a(b(4c)))
*/

#include<bits/stdc++.h>
using namespace std;
pair<int,int> st[800005],tv[500005],c[500005];
int f[200005],f2[200005],n,m,q,nx[200005],l[200005],r[200005],cnt,cnt2,u,v,x[200005],p[200005],cs[200005],deg[200005],vt[200005],L,R;
vector<int> vec[200005];
bool kt[300005];
set<int> s;
set<int> :: iterator it;
void up(int id,int l,int r,int vt,int gt)
{
    if (l>r || l>vt || r<vt) return;
    if (l==r)
    {
        st[id]={gt,vt};
        return;
    }
    int mid=(l+r)/2;
    up(id*2,l,mid,vt,gt);
    up(id*2+1,mid+1,r,vt,gt);
    st[id]=max(st[id*2],st[id*2+1]);
}
pair<int,int> get(int id,int l,int r,int u,int v)
{
    if (l>r || l>v || r<u) return {0,0};
    if (l>=u && r<=v) return st[id];
    int mid=(l+r)/2;
    return max(get(id*2,l,mid,u,v),get(id*2+1,mid+1,r,u,v));

}
int phin(int u)
{
    return f[u]<0 ? u : f[u]=phin(f[u]);
}
void uni(int u,int v)
{
    if (f[u]>f[v]) swap(u,v);
    f[u]+=f[v];
    f[v]=u;
}
int phin2(int u)
{
    return f2[u]<0 ? u : f2[u]=phin(f2[u]);
}
void uni2(int u,int v,int i)
{
    if (f2[u]>f2[v]) swap(u,v);
    nx[r[u]]=l[v];
    deg[l[v]]++;
    x[r[u]]=i;
    r[u]=r[v];
    f2[u]+=f2[v];
    f2[v]=u;
}
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m>>q;bool db=false;
    if (n==96 && m==141 & q==151) db=true;
    for (int i=1;i<=n;++i) cin>>p[i];
    memset(f,-1,sizeof(f));
    for (int i=1;i<=m;++i) cin>>c[i].first>>c[i].second;
    for (int i=1;i<=q;++i)
     {
         cin>>tv[i].first>>tv[i].second;
         if (tv[i].first==2) kt[tv[i].second]=true;
     }
    for (int i=1;i<=m;++i)
     if (!kt[i])
    {
        u=c[i].first;
        v=c[i].second;
        u=phin(u);
        v=phin(v);
        if (u!=v) uni(u,v);
    }
    for (int i=1;i<=n;++i)
     if (i==phin(i)) {++cnt;l[cnt]=r[cnt]=cnt;cs[i]=cnt;}
    for (int i=1;i<=n;++i)
     vec[cs[phin(i)]].push_back(i);
    memset(f2,-1,sizeof(f2));
    for (int i=q;i>0;--i)
     if (tv[i].first==2)
    {
        u=c[tv[i].second].first;
        v=c[tv[i].second].second;
        u=cs[phin(u)];
        v=cs[phin(v)];
        u=phin2(u);
        v=phin2(v);
        if (u!=v) uni2(u,v,i);
    }
    memset(cs,0,sizeof(cs));
    s.insert(0);

    for (int i=1;i<=cnt;++i)
     if (deg[i]==0)
    {
        u=i;
        while (1)
        {
            for (int j=0;j<vec[u].size();++j) {++cnt2;up(1,1,n,cnt2,p[vec[u][j]]);vt[vec[u][j]]=cnt2;}
            if (nx[u])
             {
                 cs[x[u]]=cnt2;
                 u=nx[u];
             }
             else break;
            if (cnt2>n) {cout<<-1;return 0;}
        }
        s.insert(cnt2);

    }

    for (int i=1;i<=q;++i)
    {
        if (tv[i].first==1)
        {
           it=s.lower_bound(vt[tv[i].second]);
           R=(*it);
           it--;
           L=(*it)+1;
           pair<int,int> X=get(1,1,n,L,R);
           cout<<X.first<<'\n';
           up(1,1,n,X.second,0);
        }
        else s.insert(cs[i]);
    }

    return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define ls (x<<1)
#define rs (x<<1|1)
#define db double
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define ull unsigned long long
using namespace std;
typedef pair<int,int> PII;
int inline read(){
    int num=0,neg=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')neg=-1;c=getchar();}
    while(isdigit(c)){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*neg;
}
const int maxn=500010,mod=998244353;
int n,m,q,p[maxn],cnt,fa[maxn],tot;
struct Q{
	int t,x;
}a[maxn];
struct Edge{
	int u,v,w;
}edge[maxn];
bool cmp(Edge x,Edge y){
	return x.w>y.w;
}
int Find(int x){
	return fa[x]==x?x:fa[x]=Find(fa[x]);
}vector<int>G[maxn];int val[maxn];
void kruskal(){
	for(int i=1;i<=2*n;i++)fa[i]=i;tot=n;
	for(int i=1;i<=m;i++){
		int x=Find(edge[i].u),y=Find(edge[i].v);
		if(x!=y){
			++tot;fa[x]=fa[y]=tot;val[tot]=edge[i].w;
			G[tot].pb(x);G[tot].pb(y);
		}
	}++tot;
	for(int i=1;i<tot;i++)
		if(fa[i]==i)G[tot].pb(i);
}int dfn[maxn],c,rev[maxn],L[maxn],R[maxn],jmp[maxn][21],dep[maxn];
void dfs(int x){
	for(int i=1;i<=20;i++)jmp[x][i]=jmp[jmp[x][i-1]][i-1];
	if(!G[x].size()){
		dfn[x]=++c;rev[c]=x;L[x]=c;R[x]=c;return;
	}L[x]=inf;R[x]=0;
	for(int i=0;i<G[x].size();i++){
		int v=G[x][i];dep[v]=dep[x]+1;jmp[v][0]=x;dfs(v);
		L[x]=min(L[x],L[v]);R[x]=max(R[x],R[v]);
	}
}
int sum[maxn<<2],pos[maxn<<2];
void pushup(int x){
	if(sum[ls]>sum[rs])pos[x]=pos[ls];
	else pos[x]=pos[rs];
	sum[x]=max(sum[ls],sum[rs]);
}
void update(int x,int l,int r,int P,int k){
	if(l==r){
		sum[x]=k;pos[x]=rev[l];return;
	}int mid=l+r>>1;
	if(mid>=P)update(ls,l,mid,P,k);
	if(mid<P)update(rs,mid+1,r,P,k);pushup(x);
}
int Query(int x,int l,int r,int L,int R){
	if(l>=L&&r<=R)return pos[x];
	int mid=l+r>>1,posl=0,posr=0,ans=0;
	if(mid>=L)posl=Query(ls,l,mid,L,R);
	if(mid<R)posr=Query(rs,mid+1,r,L,R);
	if(p[posl]>=p[ans])ans=posl;
	if(p[posr]>=p[ans])ans=posr;return ans;
}
int main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)p[i]=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		edge[i].u=x;edge[i].v=y;edge[i].w=inf;
	}
	for(int i=1;i<=q;i++){
		int op=read(),x=read();
		if(op==1){
			a[++cnt].t=i;a[cnt].x=x;
		}else edge[x].w=i-1;
	}sort(edge+1,edge+m+1,cmp);kruskal();dep[tot]=1;dfs(tot);
	for(int i=1;i<=n;i++)update(1,1,n,dfn[i],p[i]);
	for(int i=1;i<=cnt;i++){
		int now=a[i].x;
		for(int j=20;j>=0;j--)
			if(val[jmp[now][j]]>=a[i].t)now=jmp[now][j];
		int ans=Query(1,1,n,L[now],R[now]);
		printf("%d\n",p[ans]);
		p[ans]=0;update(1,1,n,dfn[ans],p[ans]);
	}return 0;
}

#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
#define pb push_back
#define ms(v,x) memset(v,x,sizeof(v))
#define ff first
#define ss second
#define td(v) v.begin(),v.end()
#define rep(i,a,n) for (int i=(a);i<(n);i++)
#define re(v) {for(auto &_re : v) cin >> _re;}
#define rre(v){for(auto &_re : v) for(auto &_rre : _re) cin >> _rre;}
#define pr(v) {for(auto _pr : v) cout << _pr << " "; cout << endl;}
#define prr(v) {for(auto _prr : v) cout << _prr.ff << " " << _prr.ss << endl;}
#define pii pair<int,int>
#define pll pair<ll,ll>
#define eb emplace_back
using namespace std;
const ll M = 1e9 + 7;
const ll mod = 998244353;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

ll binpow(ll a, ll b, ll m){
  ll res = 1;
  while(b > 0){
    if(b&1) res = res * a % m;
    a = a * a % m;
    b>>=1;
  }
  return res;
}
ll gcd(ll a, ll b){
  return (b==0 ? a : gcd(b,a%b));
}
struct dsu{ // dsu with rollback
	struct op{
		int u, l, t;
		op(){}
		op(int u,int l,int t) : u(u), l(l), t(t){}
	};
	vector<int> pai, tam;
	stack<op> old_pai;
	stack<op> old_tam;
	vector<int> g[200200];
	dsu(){}
	dsu(int n){
		pai.resize(n);
		tam = pai;
		for(int i=0;i<n;i++){
			pai[i] = i;
			tam[i] = 1;
		}
	}
	vector<int> at;
	void init(vector<int> &v){
		at.resize(v.size() + 1);
		for(int i=0;i<v.size();i++){
			g[i].eb(v[i]);
			at[v[i]] = i;
		}
	}
	int find(int u){
		if(pai[u] == u) return u;
		return find(pai[u]);
	}
	void merge(int u, int v, int t){ // merges u and v at time T;
		int a = find(u);
		int b = find(v);
		if(a==b) return;
		if(tam[a] > tam[b]) swap(a, b);
		old_pai.emplace(a, pai[a], t);
		old_tam.emplace(b, tam[b], t);
		pai[a] = b;
		tam[b] += tam[a];
		for(int &x : g[a]){
			g[b].push_back(x);
			at[x] = b;
		}
	}
	void query(int v){
		v = find(v);
		int go = 0;
		while(!g[v].empty()){
			int u = g[v].back();
			g[v].pop_back();
			if(u == 0 or at[u] != v) continue;
			else{
				go = u;
				at[u] = -1;
				break;
			}
		}
		cout << go << endl;
	}
	void rollback(int t){
		while(!old_pai.empty() && old_pai.top().t >= t){ // rolls back until time = t-1
			pai[old_pai.top().u] = old_pai.top().l;
			tam[old_tam.top().u] = old_tam.top().l;
			for(int &x : g[old_pai.top().l]){
				at[x] = old_pai.top().l;
			}
			old_pai.pop();
			old_tam.pop();
		}
	}
};
void solve(){
  int n,m,q;
  cin >> n >> m >> q;
  vector<int> p(n), er(m);
  re(p);
  vector<pii> e(m);
  for(int i=0;i<m;i++){
  	cin >> e[i].ff >> e[i].ss;
  	e[i].ff--; e[i].ss--;
  }
  vector<pii> qs(q);
  for(int i=0;i<q;i++){
  	cin >> qs[i].ff >> qs[i].ss;
  	qs[i].ss--;
  	if(qs[i].ff == 2) er[qs[i].ss] = 1;
  }
  dsu D(n);
  D.init(p);
  for(int i=0;i<m;i++){
  	if(er[i]) continue;
  	D.merge(e[i].ff, e[i].ss, 0);
  }
  int t = 1;
  for(int i=q-1;i>=0;i--){
  	if(qs[i].ff == 2){
  		D.merge(e[qs[i].ss].ff, e[qs[i].ss].ss, t++);
  	}
  }
  for(int i=0;i<n;i++) sort(td(D.g[i]));
  for(int i=0;i<q;i++){
  	if(qs[i].ff == 1){
  		D.query(qs[i].ss);
  	}
  	else{
  		D.rollback(--t);
  	}
  }
}
int32_t main(){
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int t=1;
  //cin >> t;
  while(t--){
    solve();
  }
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;

#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)

typedef long long ll;
typedef pair<int,int> pii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> indexed_set;

const int maxN = 200005;
const int maxM = 300005;
const int maxQ = 500005;
const int INF = (int)2e9;

int N, M, Q, P[maxN], par[maxN], T[maxN];
pii E[maxM], Qs[maxQ];
bitset<maxM> f;
set<pii> sets[maxQ], elems[maxN];

void init(){
	for(int i=1; i<=N; ++i){
		elems[i].clear();
		elems[i].insert(mp(N-P[i], i));
		par[i] = -1;
	}
}

int find_root(int n){
	if(par[n]==-1) return n;
	return par[n]=find_root(par[n]);
}

bool unionAB(int a, int b, int i){
	a = find_root(a);
	b = find_root(b);
	if(a==b) return false;
	if(elems[a].size()>elems[b].size()) swap(a, b);
	if(i) sets[i] = elems[a];
	for(pii p : elems[a]) elems[b].insert(p);
	elems[a].clear();
	par[a] = b;
	return true;
}

bool unionAB(int a, int b){
	return unionAB(a, b, 0);
}

int main(){
	cin.sync_with_stdio(0);
	cin.tie(0);
	cin >> N >> M >> Q;
	for(int i=1; i<=N; ++i) cin >> P[i];
	for(int i=1; i<=M; ++i){
		int a, b; cin >> a >> b;
		E[i] = mp(a, b);
	}
	for(int i=1; i<=Q; ++i){
		int op, x;
		cin >> op >> x;
		Qs[i] = mp(op, x);
		if(op==2) f[x] = 1;
	}
	init();
	for(int i=1; i<=M; ++i){
		if(f[i]) continue;
		unionAB(E[i].first, E[i].second);
	}
	int x;
	for(int i=Q; i>0; --i){
		if(Qs[i].first==1) continue;
		x = Qs[i].second;
		unionAB(E[x].first, E[x].second, i);
	}
	init();
	vector<set<pii>> vec;
	for(int i=1; i<=M; ++i) unionAB(E[i].first, E[i].second);
	for(int i=1; i<=N; ++i){
		if(par[i]==-1){
			T[i] = (int)vec.size();
			vec.pb(elems[i]);
		}
	}
	for(int i=1; i<=N; ++i) T[i] = T[find_root(i)];
	for(int i=1; i<=Q; ++i){
		int op = Qs[i].first;
		x = Qs[i].second;
		if(op==1){
			if(vec[T[x]].empty()) printf("0\n");
			else{
				auto y = vec[T[x]].begin();
				pii p = mp(N, (*y).second);
				printf("%d\n", N-(*y).first);
				vec[T[x]].erase(y);
				vec[T[x]].insert(p);
			}
		}else{
			vec.pb(sets[i]);
			for(pii p : sets[i]){
				vec[T[p.second]].erase(p);
				T[p.second] = (int)vec.size()-1;
			}
		}
	}
	return 0;
}

#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef pair<int,int> P;
const int maxn=500003;
struct edge{int u,v;}e[maxn];
int n,m,Q,a[maxn],q[maxn][4],f[maxn],ee[maxn],sz[maxn];
bool vis[maxn];
set<int> g[maxn];
set<P> st[maxn];
int find(int x){while(f[x])x=f[x];return x;}
void dfs(int u,int last,int fu,int fv){
    st[fu].emplace(a[u],u),st[fv].erase(P(a[u],u));
    for(int v:g[u]){
        if(v==last)continue;
        dfs(v,u,fu,fv);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=n;i++)scanf("%d",a+i),sz[i]=1;
    for(int i=1;i<=m;i++)scanf("%d%d",&e[i].u,&e[i].v);
    int syk=0;
    for(int i=1;i<=Q;i++){
        scanf("%d%d",&q[i][0],&q[i][1]);
        if(q[i][0]==2)ee[++syk]=i,vis[q[i][1]]=1;
    }
    for(int i=1;i<=m;i++)if(!vis[i]){
        int fu=find(e[i].u),fv=find(e[i].v);
        if(fu!=fv){
            if(sz[fu]>sz[fv])swap(fu,fv);
            g[e[i].u].insert(e[i].v),g[e[i].v].insert(e[i].u);
            f[fu]=fv,sz[fv]+=sz[fu];
        }
    }
    for(int i=syk;i>=1;i--){
        int ii=q[ee[i]][1],fu=find(e[ii].u),fv=find(e[ii].v);
        if(fu!=fv){
            q[ee[i]][0]=3;
            if(sz[fu]>sz[fv])swap(fu,fv),swap(e[ii].u,e[ii].v);
            q[ee[i]][2]=fu,q[ee[i]][3]=fv;
            g[e[ii].u].insert(e[ii].v),g[e[ii].v].insert(e[ii].u);
            f[fu]=fv,sz[fv]+=sz[fu];
        }
    }
    for(int i=1;i<=n;i++)st[find(i)].emplace(a[i],i);
    for(int i=1;i<=Q;i++){
        if(q[i][0]==1){
            int tmp=find(q[i][1]);
            if(st[tmp].empty())puts("0");
            else{
                auto it=--st[tmp].end();
                printf("%d\n",it->fi);
                st[tmp].erase(it);
            }
        }
        if(q[i][0]==3){
            int u=e[q[i][1]].u,v=e[q[i][1]].v,fu=q[i][2],fv=q[i][3];
            f[fu]=0;
            g[u].erase(v),g[v].erase(u);
            dfs(u,v,fu,fv);
        }
// printf("i:%d ST:\n",i);for(int j=1;j<=n;j++){printf("rt:%d st:",j);for(auto l:st[j])printf(" %d",l.se);puts("");}
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
int Read() {
	int x = 0, f = 1; char ch = getchar();
	while(!isdigit(ch)) {if(ch == '-')  f = -1; ch = getchar();}
	while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
	return x * f;
}
int first[600005], nxt[600005], to[600005], tot = 0;
void Add(int x, int y) {
	nxt[++tot] = first[x];
	first[x] = tot;
	to[tot] = y;
}
int ex[300005], ey[300005], vis[300005], rt[200005], tag[200005];
int sz[200005], bh[200005], a[200005], opt[200005], x[200005], vvis[200005], maxn[200005], minn[200005];
int L[200005], R[200005], rev[200005], mx[800005], Pos[800005];
void pushup(int o) {
	if(mx[o << 1] > mx[o << 1 | 1])  mx[o] = mx[o << 1], Pos[o] = Pos[o << 1];
	else  mx[o] = mx[o << 1 | 1], Pos[o] = Pos[o << 1 | 1];
}
void build(int o, int l, int r) {
	if(l == r) {mx[o] = a[rev[l]]; Pos[o] = l; return ;}
	int mid = (l + r) >> 1;
	build(o << 1, l, mid);
	build(o << 1 | 1, mid + 1, r);
	pushup(o);
}
void modify(int o, int l, int r, int pos, int val) {
	if(l == r) {mx[o] = val; return ;}
	int mid = (l + r) >> 1;
	if(pos <= mid)  modify(o << 1, l, mid, pos, val);
	else  modify(o << 1 | 1, mid + 1, r, pos, val);
	pushup(o);
}
pair<int, int> my_max(pair<int, int> A, pair<int, int> B) {
	return (A.first > B.first) ? A : B;
}
pair<int, int> query(int o, int l, int r, int nl, int nr) {
	if(nl <= l && r <= nr)  return make_pair(mx[o], Pos[o]);
	int mid = (l + r) >> 1; pair<int, int> ans;
	ans.first = ans.second = 0;
	if(nl <= mid)  ans = my_max(ans, query(o << 1, l, mid, nl, nr));
	if(mid < nr)  ans = my_max(ans, query(o << 1 | 1, mid + 1, r, nl, nr));
	return ans;
}
int findfa(int x) {return rt[x] == x ? x : rt[x] = findfa(rt[x]);}
void dfs(int u) {
	vvis[u] = 1;
	bh[u] += tag[u];
	for(int e = first[u]; e; e = nxt[e]) {
		int v = to[e];
		tag[v] += tag[u];
		dfs(v);
	}
}
signed main() {
	int n = Read(), m = Read(), q = Read();
	for(int i = 1; i <= n; i++)  sz[i] = bh[i] = 1, rt[i] = i, a[i] = Read();
	for(int i = 1; i <= m; i++)  ex[i] = Read(), ey[i] = Read();
	for(int i = 1; i <= q; i++) {
		opt[i] = Read(), x[i] = Read();
		if(opt[i] == 2)  vis[x[i]] = 1;
	}
	for(int i = 1; i <= m; i++) {
		if(!vis[i]) {
			int fx = findfa(ex[i]), fy = findfa(ey[i]);
			if(fx == fy)  continue;
			tag[fx] += sz[fy];
			sz[fy] += sz[fx]; rt[fx] = fy;
			Add(fy, fx);
		}
	}
	for(int i = q; i >= 1; i--) {
		if(opt[i] == 2) {
			int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
			if(fx == fy)  continue;
			tag[fx] += sz[fy];
			sz[fy] += sz[fx]; rt[fx] = fy;
			Add(fy, fx);
		}
	}
	int sum = 0;
	for(int i = 1; i <= n; i++)
		if(!vvis[findfa(i)])  tag[rt[i]] += sum, sum += sz[rt[i]], dfs(rt[i]);
	for(int i = 1; i <= n; i++)
		maxn[i] = minn[i] = bh[i], rt[i] = i, rev[bh[i]] = i;
	for(int i = 1; i <= m; i++) {
		if(!vis[i]) {
			int fx = findfa(ex[i]), fy = findfa(ey[i]);
			if(fx == fy)  continue;
			maxn[fy] = max(maxn[fy], maxn[fx]);
			minn[fy] = min(minn[fy], minn[fx]);
			rt[fx] = fy;
		}
	}
	for(int i = q; i >= 1; i--) {
		if(opt[i] == 2) {
			int fx = findfa(ex[x[i]]), fy = findfa(ey[x[i]]);
			if(fx == fy)  continue;
			maxn[fy] = max(maxn[fy], maxn[fx]);
			minn[fy] = min(minn[fy], minn[fx]);
			rt[fx] = fy;
		}
		if(opt[i] == 1)
			L[i] = minn[findfa(x[i])], R[i] = maxn[findfa(x[i])];
	}
	build(1, 1, n);
	for(int i = 1; i <= q; i++) {
		if(opt[i] == 1) {
			pair<int, int> tmp = query(1, 1, n, L[i], R[i]);
			printf("%d\n", tmp.first);
			modify(1, 1, n, tmp.second, 0);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10+MAXM, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], rp[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM], qs[MAXQ];
bool del[MAXN], used[MAXM];

int find_set(int v){
    return v==rp[v]?v:rp[v]=find_set(rp[v]);
}
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; rp[b] = a; sz[b]=0;
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}

void fsc(int &x){
    register int c;
    x = 0; c=getchar();
    for(;(c>47 && c<58);c=getchar())
        x = (x<<1) + (x<<3) +c -48;
}
void solve(){
    fsc(n), fsc(m), fsc(q);
    for (int i = 0; i < n; i++) fsc(a[i]);
    for (int i = 0; i < m; i++) fsc(ed[i][0]), fsc(ed[i][1]), ed[i][0]--, ed[i][1]--;
    memset(used, 0, sizeof(used));
    for (int i = 0; i < q; i++){
        ar<int, 2> c; fsc(c[0]), fsc(c[1]), --c[1];
        qs[i]=c; if (c[0] == 2) used[c[1]]=1;
    }
    for (int i = 0; i < m; i++) if (!used[i]) qs[q] = ar<int, 2>{2, i}, q++;
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    iota(p, p+n, 0); fill(sz, sz+n, 1); iota(rp, rp+n, 0); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        if (p[i] != i) ch[p[i]].push_back(i);
        loc[i] = find_set(i); ans[loc[i]].insert({a[i], i});
    }
    for (int i = 0; i < q; i++){
        auto c = qs[i]; continue;
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << "0\n"; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            cout << cans[0] << '\n'; er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1 || v==loc[v]) continue;
            dfs(v, loc[v], v);
        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mp make_pair
#define pb push_back
#define VI vector<int>
#define pii pair<int,int>
using namespace std;
const int MAXN = 5e5+10;
int u[MAXN], v[MAXN], per[MAXN];
int su[MAXN], sv[MAXN];
bool rmv[MAXN];
int p[MAXN];
int n, m, q;
int qi[MAXN], val[MAXN], sz[MAXN];
int find(int x){
	if(p[x] == x) return x;
	return p[x] = find(p[x]);
}
void join(int x, int y){
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
bool out[MAXN];
set<int> S[MAXN];
int ss;
int where[MAXN];
vector<pii> g[MAXN];
bool V[MAXN];
int vis;
void dfs(int cur, int prev, int to){
	V[cur] = true;
	where[cur] = to;
	S[to].insert(cur);
	for(int i = 0; i < (int)g[cur].size(); i++){
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs(next, cur, to);
	}
}
void dfs1(int cur, int prev, int from, int to){
	vis++;
	S[from].erase(cur);
	if(!out[cur]) S[to].insert(cur);
	else S[to].insert(0);
	where[cur] = to;
	for(int i = 0; i < (int)g[cur].size(); i++){
		if(rmv[g[cur][i].second]) continue;
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs1(next, cur, from, to);
	}
}
int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(int i = 1; i <= n; i++){
		scanf("%d", &per[i]);
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= m; i++){
		scanf("%d %d", &u[i], &v[i]);
		u[i] = per[u[i]];
		v[i] = per[v[i]];
	}
	for(int i = 0; i < q; i++){
		scanf("%d %d", &qi[i], &val[i]);
		if(qi[i] == 2) rmv[val[i]] = true;
		else val[i] = per[val[i]];
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		if(find(u[i]) == find(v[i])) continue;
		join(u[i], v[i]);
	}
	for(int i = q-1; i >= 0; i--){
		if(qi[i] == 2){
			//ru[i] = find(u[val[i]]);
			//rv[i] = find(v[val[i]]);
			int x = u[val[i]], y = v[val[i]];
			if(find(x) == find(y)){
				su[i] = sv[i] = -1;
				continue;
			}
			su[i] = sz[find(x)];
			sv[i] = sz[find(y)];
			g[x].pb(mp(y,val[i]));
			g[y].pb(mp(x,val[i]));
			join(x, y);

		}
	}
	for(int i = 1; i <= n; i++){
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < (int)g[i].size(); j++){
			int x = i, y = g[i][j].first;
			join(x, y);
		}
	}
	for(int i = 1; i <= m; i++){
		int x = u[i], y = v[i];
		if(find(x) == find(y)) continue;
		g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
		join(x, y);
	}
	ss = 0;
	memset(V, false, sizeof V);
	for(int i = 1; i <= n; i++){
		if(!V[i]) dfs(i, i, ss++);
	}
	for(int i = 1; i <= m; i++) rmv[i] = false;
	for(int i = 0; i < q; i++){
		if(qi[i] == 1){
			int cur = val[i];
			int w = where[cur];
			int ans = *S[w].rbegin();
			printf("%d\n", ans);
			if(ans){
				out[ans] = true;
				S[w].erase(ans);
				S[w].insert(0);
			}
		}else{
			rmv[val[i]] = true;
			if(su[i] == -1) continue;
			int ei = val[i];
			if(su[i] < sv[i]){
				vis = 0;
				dfs1(u[ei], u[ei], where[u[ei]], ss++);
				if(vis != su[i]){
					printf("%d %d\n", vis, su[i]);
					return 0;
				}
			}else{
				vis = 0;
				dfs1(v[ei], v[ei], where[v[ei]], ss++);
				if(vis != sv[i]){
					printf("%d %d\n", vis, sv[i]);
					return 0;
				}
			}
		}
	}
	return 0;
}

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 500100;

int v[MAXN];
pair<int,int> grafo[MAXN] , q[MAXN];
bool are[MAXN];
int p[MAXN];

int pai[MAXN];
vector<int> vec[MAXN];

struct seg{
	seg *fe,*fd;
	int meio,l,r;
	pair<int,int> mex;

	seg(int x,int y){
		meio = (x + y) / 2;
		l = x , r = y;
		mex = {-1,0};

		if(l == r) return;

		fe = new seg(x,meio);
		fd = new seg(meio + 1,y);
	}

	void up(int pos,int novo){
		if(l == r){
			mex = {novo,l};
			return;
		}
		if(pos <= meio) fe->up(pos,novo);
		else fd->up(pos,novo);

		if(fe->mex.first >= fd->mex.first) mex = fe->mex;
		else mex = fd->mex;
	}

	pair<int,int> get(int a,int b){
		if(l >= a && r <= b) return mex;
		if(l > b || r < a) return {-1,0};

		pair<int,int> re = fe->get(a,b) , rd = fd->get(a,b);

		if(re.first >= rd.first) return re;
		return rd;
	}
};

int find(int x){
	if(pai[x] == x) return x;
	return pai[x] = find(pai[x]);
}

void join(int a,int b){
	a = find(a) , b = find(b);

	if(vec[a].size() >= vec[b].size()){
		for(int i = 0;i < vec[b].size();i++)
			vec[a].push_back(vec[b][i]);
		pai[b] = a;
	}
	else{
		for(int i = 0;i < vec[a].size();i++)
			vec[b].push_back(vec[a][i]);
		pai[a] = b;
	}
}

seg st(0,MAXN);

int main(){

	int n,m,Q;
	cin >> n >> m >> Q;

	for(int i = 1;i <= n;i++) cin >> v[i] , pai[i] = i , vec[i].push_back(i);

	for(int i = 1;i <= m;i++) cin >> grafo[i].first >> grafo[i].second;

	if(n > 100) return 0;

	for(int i = 1;i <= Q;i++){
		cin >> q[i].first >> q[i].second;
		if(q[i].first == 2) are[q[i].second] = true;
	}

	for(int i = 1;i <= m;i++){
		if(are[i] == true) continue;
		int a = grafo[i].first , b = grafo[i].second;
		if(find(a) == find(b)) continue;
		join(a,b);
	}

	vector<pair<int,int>> res;

	for(int i = Q;i >= 1;i--){
		if(q[i].first == 1){
			int a = find(q[i].second);
			res.push_back({a,vec[a].size()});
			//cout << "// " << a << " " << vec[a].size() << endl;
		}
		else{
			int a = find(grafo[q[i].second].first) , b = find(grafo[q[i].second].second);
			if(a == b) continue;
			join(a,b);
		}

		//for(int j = 1;j <= n;j++) cout << "|| " << j << " " << find(j) << endl;
		//cout << endl;
	}

	for(int i = 1;i < n;i++){
		if(find(i) == find(i + 1)) continue;
		join(i,i + 1);
	}

	if(n > 100) return 0;

	int h = find(1);
	for(int i = 0;i < n;i++) p[vec[h][i]] = i + 1 , st.up(i + 1,v[vec[h][i]]); //,cout << "/ " << i + 1 << " " << vec[h][i] << endl;

	for(int i = (int) res.size() - 1;i >= 0;i--){
		pair<int,int> h = st.get(p[res[i].first],p[res[i].first] + res[i].second - 1);
		cout << h.first << endl;
		st.up(h.second,0);
	}

}

#include <bits/stdc++.h>
using namespace std;
typedef long double ld;
typedef long long ll;
typedef pair<double, double> pdd;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef pair<int, int> pii;
typedef vector<pii> vii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<string> vs;
//const int mod = ;

vi p, sz, in, out;
vvi g;
int TIME = 0;

void dfs(int v) {
  ++TIME;
  in[v] = TIME;
  for (int nv : g[v]) {
    dfs(nv);
    sz[v] += sz[nv];
  }
  out[v] = TIME;
  //cerr << "dfs: " << v + 1 << ' ' << in[v] << ' ' << out[v] << endl;
}

int getp(int v) {
  if (p[v] == v) return v;
  return p[v] = getp(p[v]);
}

int join(int a, int b) {
  a = getp(a);
  b = getp(b);
  if (a == b) return -1;
  p[a] = b;
  g[b].push_back(a);
  return b;
}

const int N = 1 << 18;
pii ma[2 * N];

int main() {
  std::ios::sync_with_stdio(false); std::cin.tie(0);
  int n, m, Q;
  cin >> n >> m >> Q;
  vi a(n);
  p.resize(n);
  g.resize(n);
  sz.assign(n, 0);
  in.assign(n, 0);
  out.assign(n, 0);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
    p[i] = i;
  }
  vector<array<int, 2>> e(m);
  for (int i = 0; i < m; ++i) {
    cin >> e[i][0] >> e[i][1];
    --e[i][0];
    --e[i][1];
  }
  vi del(m);
  vector<array<int, 2>> q(Q);
  for (int i = 0; i < Q; ++i) {
    cin >> q[i][0] >> q[i][1];
    --q[i][1];
    if (q[i][0] == 2) del[q[i][1]] = 1;
  }
  for (int i = 0; i < m; ++i) if (!del[i]) join(e[i][0], e[i][1]);
  for (int i = Q - 1; i >= 0; --i) {
    if (q[i][0] == 1) {
      q[i][1] = getp(q[i][1]);
    } else {
      q[i][1] = join(e[q[i][1]][0], e[q[i][1]][1]);
    }
  }
  for (int i = 0; i < n; ++i) if (p[i] == i) dfs(i);
  for (int i = N; i < 2 * N; ++i) ma[i] = pii(-1, i - N);
  for (int i = 0; i < n; ++i) {
    ma[in[i] + N].first = a[i];
  }
  for (int i = N - 1; i > 0; --i) ma[i] = max(ma[2 * i], ma[2 * i + 1]);
  for (int t = 0; t < Q; ++t) {
    int v = q[t][1];
    if (q[t][0] == 1) {
      int l = in[v] + N, r = out[v] + N;
      pii best(0, in[v]);
      while (l <= r) {
        if (l & 1) {
          best = max(best, ma[l]);
          ++l;
        }
        if (!(r & 1)) {
          best = max(best, ma[r]);
          --r;
        }
        l /= 2;
        r /= 2;
      }
      int u = best.second;
      //cerr << v + 1 << ' ' << u + 1 << ' ';
      cout << best.first << '\n';
      int x = u + N;
      ma[x].first = 0;
      while (x > 1) {
        x /= 2;
        ma[x] = max(ma[2 * x], ma[2 * x + 1]);
      }
    } else if (v >= 0) {
      assert(!g[v].empty());
      out[v] -= sz[g[v].back()];
      g[v].pop_back();
    }
  }
  return 0;
}

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<tuple>
#include<cassert>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
const ll mod = 1000000007;
const ll INF = (ll)1000000007 * 1000000007;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define Per(i,sta,n) for(int i=n-1;i>=sta;i--)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef long double ld;
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<ll, ll> LP;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
template<class T>bool chmax(T &a, const T &b) {if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T &a, const T &b) {if(b<a){a=b;return 1;}return 0;}

template <class S, S (*op)(S, S), S (*e)()> struct SegmentTree {
  public:
    SegmentTree() : SegmentTree(0) {}
    SegmentTree(int n) : SegmentTree(std::vector<S>(n, e())) {}
    SegmentTree(const std::vector<S>& v) : _n(int(v.size())) {
        log = ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set_val(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S query(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_query() { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) {//f(op([l,r)))==trueを満たす最大のr
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) {//f(op([l,r)))==trueを満たす最小のl
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }

    int ceil_pow2(int n) {
        int x = 0;
        while ((1U << x) < (unsigned int)(n)) x++;
        return x;
    }
};

struct UnionFind {
private:
    vector<int> par,ran;
    vector<int> edge,size;
    int n;
public:
    UnionFind(int x){
      n=x;
      par.resize(n,0);
      ran.resize(n,0);
      edge.resize(n,0);
      size.resize(n,1);
      rep(i,n){
        par[i]=i;
      }
    }
    int find(int x) {
        if (par[x]==x)return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x, int y) {
        x=find(x),y=find(y);
        if (x==y){
            edge[x]++;
            return;
        }
        if (ran[x]<ran[y]) {
            par[x]=y;
            size[y]+=size[x];
            edge[y]+=edge[x]+1;
        }
        else {
            par[y]=x;
            size[x]+=size[y];
            edge[x]+=edge[y]+1;
            if (ran[x]==ran[y])ran[x]++;
        }
    }
    bool same(int x,int y) {
        return find(x)==find(y);
    }
    int getSize(int x){
        return size[find(x)];
    }
    int getEdge(int x){
        return edge[find(x)];
    }
};

struct T{
  int idx,h;
  T(int h,int idx):h(h),idx(idx){}
  T(){}
};

T F(T a,T b){
  if(a.h>=b.h) return a;
  return b;
}

T e1(){return T(0,0);}

int n,m,q;
int a[200010];
P e[300010],qs[500010];
vector<int> G[600010];
vector<int> S[500010];
vector<bool> is_root;
P sec[600010];
int p[300010],inv[300010];

void dfs(int s,int &id){
  if(G[s].empty()) {
    id++;
    p[id]=s;
    inv[s]=id;
  }
  //cout << s << " " << id << endl;
  sec[s].first=id+1-(G[s].empty());
  for(int t:G[s]){
    dfs(t,id);
  }
  sec[s].second=id+1;
}

void solve(){
  scanf("%d%d%d",&n,&m,&q);
  rep(i,n) scanf("%d",&a[i]);
  rep(i,m){
    scanf("%d%d",&e[i].first,&e[i].second);
    e[i].first--;e[i].second--;
  }
  vector<P> units={};
  vector<bool> used(m,false);
  rep(i,q){
    scanf("%d%d",&qs[i].first,&qs[i].second);
    qs[i].second--;
    if(qs[i].first==2) {
      units.push_back(P(i,qs[i].second));
      used[qs[i].second]=true;
    }
  }
  rep(i,m){
    if(!used[i]) units.push_back(P(q,i));
  }
  int U=n;
  UnionFind uf(n);is_root.resize(n,true);
  vector<int> nodes(n);rep(i,n) nodes[i]=i;
  per(i,units.size()){
    P u=units[i];
    //cout << i << " " << e[u.second].first << " " << e[u.second].second << endl;
    if(uf.same(e[u.second].first,e[u.second].second)) continue;
    G[U].push_back(nodes[uf.find(e[u.second].first)]);
    G[U].push_back(nodes[uf.find(e[u.second].second)]);
    is_root[nodes[uf.find(e[u.second].first)]]=false;
    is_root[nodes[uf.find(e[u.second].second)]]=false;
    is_root.push_back(true);
    uf.unite(e[u.second].first,e[u.second].second);
    nodes[uf.find(e[u.second].first)]=U;
    S[u.first].push_back(U);
    U++;
  }
  int id=-1;
  set<P> se;
  rep(i,U){
    if(!is_root[i]) continue;
    dfs(i,id);
    se.insert(P(sec[i].first,sec[i].second));
  }
  vector<T> vec(n);
  rep(i,n) vec[i]=T(a[p[i]],i);
  SegmentTree<T,F,e1> seg(vec);
  //rep(i,U) cout << sec[i].first << " " << sec[i].second << endl;
  rep(i,q){
    for(int z:S[i]){
      int t1=G[z][0],t2=G[z][1];
      se.erase(sec[z]);
      se.insert(sec[t1]);
      se.insert(sec[t2]);
    }
    if(qs[i].first==1){
      //cout << inv[qs[i].second] << endl;
      auto it=se.lower_bound(P(inv[qs[i].second],mod));it--;
      P p=(*it);
      //cout << p.first << " " << p.second << endl;
      T t=seg.query(p.first,p.second);
      printf("%d\n",t.h);
      seg.set_val(t.idx,T(0,t.idx));
    }
  }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(50);
    solve();
}

#include <bits/stdc++.h>

using namespace std;
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifndef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
	*this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<long long, int> pli;
typedef long long ll;
#define f first
#define s second
#define endl '\n'
#define all(x) x.begin(),x.end()
const int N=5e5+1;
int p[ N ],tin [ N ],tout[ N ],timer=0;
int get( int v ){
    return p[v] = ( v == p[v] ? v : get( p[ v ] ) );
}
int n,m,q;
vector<int> g [ N ];
pii t[ 4 * N ];
int a[ N ];
int obr[N];
void mg(int a, int b){
    int c = get( a ), d = get( b );
    if(c == d) return;
    n++;
    p[c]=n;
    p[d]=n;
    g[ n ].emplace_back(c);
    g[ n ].emplace_back(d);
    return ;
}
void dfs(int v, int p){
    tin[ v ] = ++timer;
    obr[ timer ] = v;
    for(auto &z : g[ v ]){
        dfs( z, v );
    }
    tout[ v ] = timer;
}
void b_tr(int v,int tl,int tr){
    if(tl == tr){
        t[v]={a[obr[tl]],tl};
    }
    else{
        int tm=(tl+tr)>>1;
        b_tr(2*v,tl,tm);
        b_tr(2*v+1,tm+1,tr);
        t[v]=max(t[2*v],t[2*v+1]);
    }
}
pii getMax(int l,int r,int v,int tl,int tr){
    if(tl>=l && tr<=r){
        return t[v];
    }
    if(tl>r || tr<l) return {0,n};
    int tm=(tl+tr)>>1;
    return max(getMax(l,r,2*v,tl,tm),getMax(l,r,2*v+1,tm+1,tr));
}
void upd(int id,int v,int tl,int tr){
    if(tl==tr){
        t[v].first=0;
        return ;
    }
    int tm=(tl+tr)>>1;
    if(tm>=id)
        upd(id,2*v,tl,tm);
    else
        upd(id,2*v+1,tm+1,tr);
    t[v]=max(t[2*v],t[2*v+1]);
}
pii e[N];
bool ex[N];
pii qe[N];
signed main(){
    cin.tie(0);cout.tie(0);ios_base::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0;i < m;i++){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    iota(p,p+N,0);
    for(int i = 0;i < q;i++){
        int tp;
        cin>>tp;
        int id;
        cin>>id;
        if(tp==2){
            ex[id-1]=1;
        }
        qe[i]={tp,id};
    }
    for(int i = 0; i < m;i++){
        if(!ex[i]){
            mg(e[i].f,e[i].s);
        }
    }
    for(int i = q - 1; ~ i; --i){
        if(qe[i].f==2)
            mg(e[qe[i].s-1].f,e[qe[i].s-1].s);
        else {
            qe[i].s=get(qe[i].s);
        }
    }
    for(int i = 1;i <= n; i++){
        if(get(i)==i)
            dfs(i,i);
    }
    b_tr(1,1,N-1);
    for(int i = 0; i<q; i++){
        if(qe[i].f==1){
            int id=qe[i].s;
            auto w=getMax(tin[id],tout[id],1,1,N-1);
            upd(w.s,1,1,N-1);
            cout<<w.f<<endl;
        }
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
pair<int,int> st[800005],tv[500005],c[500005];
int f[200005],f2[200005],n,m,q,nx[200005],l[200005],r[200005],cnt,cnt2,u,v,x[200005],p[200005],cs[200005],deg[200005],vt[200005],L,R;
vector<int> vec[200005];
bool kt[300005];
set<int> s;
set<int> :: iterator it;
void up(int id,int l,int r,int vt,int gt)
{
    if (l>r || l>vt || r<vt) return;
    if (l==r)
    {
        st[id]={gt,vt};
        return;
    }
    int mid=(l+r)/2;
    up(id*2,l,mid,vt,gt);
    up(id*2+1,mid+1,r,vt,gt);
    st[id]=max(st[id*2],st[id*2+1]);
}
pair<int,int> get(int id,int l,int r,int u,int v)
{
    if (l>r || l>v || r<u) return {0,0};
    if (l>=u && r<=v) return st[id];
    int mid=(l+r)/2;
    return max(get(id*2,l,mid,u,v),get(id*2+1,mid+1,r,u,v));

}
int phin(int u)
{
    return f[u]<0 ? u : f[u]=phin(f[u]);
}
void uni(int u,int v)
{
    if (f[u]>f[v]) swap(u,v);
    f[u]+=f[v];
    f[v]=u;
}
int phin2(int u)
{
    return f2[u]<0 ? u : f2[u]=phin(f2[u]);
}
void uni2(int u,int v,int i)
{
    if (f2[u]>f2[v]) swap(u,v);
    nx[r[u]]=l[v];
    deg[l[v]]++;
    x[r[u]]=i;
    r[u]=r[v];
    f2[u]+=f2[v];
    f2[v]=u;
}
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m>>q;bool db=false;
    if (n==96 && m==141 & q==151) db=true;
    for (int i=1;i<=n;++i) cin>>p[i];
    memset(f,-1,sizeof(f));
    for (int i=1;i<=m;++i) cin>>c[i].first>>c[i].second;
    for (int i=1;i<=q;++i)
     {
         cin>>tv[i].first>>tv[i].second;
         if (tv[i].first==2) kt[tv[i].second]=true;
     }
    for (int i=1;i<=m;++i)
     if (!kt[i])
    {
        u=c[i].first;
        v=c[i].second;
        u=phin(u);
        v=phin(v);
        if (u!=v) uni(u,v);
    }
    for (int i=1;i<=n;++i)
     if (i==phin(i)) {++cnt;l[cnt]=r[cnt]=cnt;cs[i]=cnt;}
    for (int i=1;i<=n;++i)
     vec[cs[phin(i)]].push_back(i);
    memset(f2,-1,sizeof(f2));
    for (int i=q;i>0;--i)
     if (tv[i].first==2)
    {
        u=c[tv[i].second].first;
        v=c[tv[i].second].second;
        u=cs[phin(u)];
        v=cs[phin(v)];
        u=phin2(u);
        v=phin2(v);
        if (u!=v) uni2(u,v,i);
    }
    memset(cs,0,sizeof(cs));
    s.insert(0);

    for (int i=1;i<=cnt;++i)
     if (deg[i]==0)
    {
        u=i;
        while (1)
        {
            for (int j=0;j<vec[u].size();++j) {++cnt2;up(1,1,n,cnt2,p[vec[u][j]]);vt[vec[u][j]]=cnt2;}
            if (nx[u])
             {
                 cs[x[u]]=cnt2;
                 u=nx[u];
             }
             else break;
            if (cnt2>n) cout<<u<<endl;
            if (cnt2-n==n) return 0;
        }
        s.insert(cnt2);

    }

    for (int i=1;i<=q;++i)
    {
        if (tv[i].first==1)
        {
           it=s.lower_bound(vt[tv[i].second]);
           R=(*it);
           it--;
           L=(*it)+1;
           pair<int,int> X=get(1,1,n,L,R);
           cout<<X.first<<'\n';
           up(1,1,n,X.second,0);
        }
        else s.insert(cs[i]);
    }

    return 0;
}

/*
 * Package: StandardCodeLibrary.Core
 * */
//引进常用的头文件并使用std名字空间;
#include <algorithm>
#include <bitset>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;

//用于减少代码量的宏;
#define lp for (;;)
#define repf(i, a, b) for (int i = (a); i < (b); ++i)
#define ft(i, a, b) for (int i = (a); i <= (b); ++i)
#define fdt(i, a, b) for (int i = (a); i >= (b); --i)
#define rrepf(i, a, b) fdt(i, (a)-1, b)
#define rep(i, n) repf(i, 0, n)
#define rrep(i, n) rrepf(i, n, 0)
#define for_each(e, s)                                                         \
  for (__typeof__((s).begin()) e = (s).begin(); e != (s).end(); ++e)
#define for_nonempty_subsets(subset, set)                                      \
  for (int subset = set; subset; subset = (subset - 1) & (set))
#define for_in_charset(i, charset) for (cstr i = (charset); *i; i++)
#define whl(x) while (x)
#define rtn return
#define fl(x, y) memset((x), char(y), sizeof(x))
#define clr(x) fl(x, char(0))
#define cpy(x, y) memcpy(x, y, sizeof(x))
#define sf scanf
#define pf printf
#define vec vector
#define pr pair
#define que queue
#define prq priority_queue
#define itr iterator
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define ins insert
#define ers erase
#define lb lower_bound
#define ub upper_bound
#define rnk order_of_key
#define sel find_by_order
#define ctz __builtin_ctz
#define clz __builtin_clz
#define bc __builtin_popcount
#define sz(x) (int((x).size()))
#define all(x) (x).begin(), (x).end()
#define srt(x) sort(all(x))
#define uniq(x) srt(x), (x).erase(unique(all(x)), (x).end())
#define rev(x) reverse(all(x))
#define shf(x) random_shuffle(all(x))
#define nxtp(x) next_permutation(all(x))

//调试相关的宏;
#ifndef DEBUG
#define prt(x) (cerr)
#define asrtWA(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      exit(0);                                                                 \
  whl(0)
#define asrtTLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      whl(1);                                                                  \
  whl(0)
#define asrtMLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      whl(new int);                                                            \
  whl(0)
#define asrtOLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      whl(1) puts("OLE");                                                      \
  whl(0)
#define asrtRE(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      *(int *)0 = 0;                                                           \
  whl(0)
#define runtime() (cerr)
#define input(in) freopen(in, "r", stdin)
#define output(out) freopen(out, "w", stdout)
#else
#define prt(x) cerr << "第" << __LINE__ << "行\t: " << #x "\t=" << (x) << endl
#define asrtWA(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtTLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtMLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtOLE(s)                                                             \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define asrtRE(s)                                                              \
  do                                                                           \
    if (!(s))                                                                  \
      cerr << "assert(" #s ")" << endl;                                        \
  whl(0)
#define runtime()                                                              \
  cerr << "Used: " << db(clock()) / CLOCKS_PER_SEC << "s" << endl
#define input(in)
#define output(out)
#endif

//常用数据类型;
typedef long long int lli;
typedef double db;
typedef const char *cstr;
typedef string str;
typedef vec<int> vi;
typedef vec<vi> vvi;
typedef vec<lli> vl;
typedef vec<vl> vvl;
typedef vec<bool> vb;
typedef vec<vb> vvb;
typedef vec<char> vc;
typedef vec<vc> vvc;
typedef vec<str> vs;
typedef pr<int, int> pii;
typedef pr<lli, lli> pll;
typedef pr<db, db> pdd;
typedef vec<pii> vpii;
typedef vec<pll> vpll;
typedef vec<pdd> vpdd;
typedef map<int, int> mii;
typedef map<str, int> msi;
typedef map<char, int> mci;
typedef set<int> si;
typedef set<str> ss;
typedef que<int> qi;

//常用常量:int的最大值;lli的最大值;db的误差相关常数;欧拉常数;圆周率;移动向量;取模使用的除数;
int oo = (~0u) >> 1;
lli ooll = (~0ull) >> 1;
db inf = 1e+10;
db eps = 1e-10;
db gam = 0.5772156649015328606;
db pi = acos(-1.0);
int dx[] = {1, 0, -1, 0, 1, -1, -1, 1, 0};
int dy[] = {0, 1, 0, -1, 1, 1, -1, -1, 0};
int MOD = 1000000007;

//常用函数:最大最小值更新;数学相关函数;输入和输出;树状数组;并查集;可合并堆;
template <typename type> inline bool cmax(type &a, const type &b) {
  rtn a < b ? a = b, true : false;
}
template <typename type> inline bool cmin(type &a, const type &b) {
  rtn b < a ? a = b, true : false;
}
template <typename type> inline type sqr(const type &x) { rtn x *x; }
template <typename type> inline type mod(const type &x) { rtn x % MOD; }
inline int sgn(const db &x) { rtn(x > +eps) - (x < -eps); }
inline int dbcmp(const db &a, const db &b) { rtn sgn(a - b); }
template <typename type>
inline pr<type, type> operator-(const pr<type, type> &x) {
  rtn mp(-x.x, -x.y);
}
template <typename type>
inline pr<type, type> operator+(const pr<type, type> &a,
                                const pr<type, type> &b) {
  rtn mp(a.x + b.x, a.y + b.y);
}
template <typename type>
inline pr<type, type> operator-(const pr<type, type> &a,
                                const pr<type, type> &b) {
  rtn mp(a.x - b.x, a.y - b.y);
}
template <typename type>
inline pr<type, type> operator*(const pr<type, type> &a, const type &b) {
  rtn mp(a.x * b, a.y * b);
}
template <typename type>
inline pr<type, type> operator/(const pr<type, type> &a, const type &b) {
  rtn mp(a.x / b, a.y / b);
}
template <typename type>
inline pr<type, type> &operator-=(pr<type, type> &a, const pr<type, type> &b) {
  rtn a = a - b;
}
template <typename type>
inline pr<type, type> &operator+=(pr<type, type> &a, const pr<type, type> &b) {
  rtn a = a + b;
}
template <typename type>
inline pr<type, type> &operator*=(pr<type, type> &a, const type &b) {
  rtn a = a * b;
}
template <typename type>
inline pr<type, type> &operator/=(pr<type, type> &a, const type &b) {
  rtn a = a / b;
}
template <typename type>
inline type cross(const pr<type, type> &a, const pr<type, type> &b) {
  rtn a.x *b.y - a.y *b.x;
}
template <typename type>
inline type dot(const pr<type, type> &a, const pr<type, type> &b) {
  rtn a.x *b.x + a.y *b.y;
}
template <typename type> inline type gcd(type a, type b) {
  if (b)
    whl((a %= b) && (b %= a));
  rtn a + b;
}
template <typename type> inline type lcm(type a, type b) {
  rtn a *b / gcd(a, b);
}
inline lli bin_pow(lli x, lli y) {
  lli z = 1;
  whl(y) {
    if (y & 1)
      z = mod(z * x);
    x = mod(sqr(x)), y >>= 1;
  }
  rtn z;
}
template <typename istream, typename first_type, typename second_type>
inline istream &operator>>(istream &cin, pr<first_type, second_type> &x) {
  rtn cin >> x.x >> x.y;
}
template <typename ostream, typename first_type, typename second_type>
inline ostream &operator<<(ostream &cout,
                           const pr<first_type, second_type> &x) {
  rtn cout << x.x << " " << x.y;
}
template <typename istream, typename type>
inline istream &operator>>(istream &cin, vec<type> &x) {
  rep(i, sz(x)) cin >> x[i];
  rtn cin;
}
template <typename ostream, typename type>
inline ostream &operator<<(ostream &cout, const vec<type> &x) {
  rep(i, sz(x)) cout << x[i] << (i + 1 == sz(x) ? "" : " ");
  rtn cout;
}
inline ostream &pdb(int prcs, db x) {
  rtn cout << setprecision(prcs) << fixed << (sgn(x) ? (x) : 0);
}
template <typename type> inline void bit_inc(vec<type> &st, int x, type inc) {
  whl(x < sz(st)) st[x] += inc, x |= x + 1;
}
template <typename type> inline type bit_sum(const vec<type> &st, int x) {
  type s = 0;
  whl(x >= 0) s += st[x], x = (x & (x + 1)) - 1;
  rtn s;
}
template <typename type> inline type bit_kth(const vec<type> &st, int k) {
  int x = 0, y = 0, z = 0;
  whl((1 << (++y)) <= sz(st));
  rrep(i, y) {
    if ((x += 1 << i) > sz(st) || z + st[x - 1] > k)
      x -= 1 << i;
    else
      z += st[x - 1];
  }
  rtn x;
}
inline void make_set(vi &st) { rep(i, sz(st)) st[i] = i; }
inline int find_set(vi &st, int x) {
  int y = x, z;
  whl(y != st[y]) y = st[y];
  whl(x != st[x]) z = st[x], st[x] = y, x = z;
  rtn y;
}
inline bool union_set(vi &st, int a, int b) {
  a = find_set(st, a), b = find_set(st, b);
  rtn a != b ? st[a] = b, true : false;
}
inline void make_set(vpii &st) { rep(i, sz(st)) st[i] = mp(i, 1); }
inline int find_set(vpii &st, int x) {
  int y = x, z;
  whl(y != st[y].x) y = st[y].x;
  whl(x != st[x].x) z = st[x].x, st[x].x = y, x = z;
  rtn y;
}
inline bool union_set(vpii &st, int a, int b) {
  a = find_set(st, a), b = find_set(st, b);
  rtn a != b ? (st[a].y > st[b].y ? st[a].x = b,
                st[a].y += st[b].y : st[b].x = a, st[b].y += st[a].y),
      true : false;
}
template <typename type> inline void merge(type &a, type &b) {
  if (sz(a) < sz(b))
    swap(a, b);
  whl(sz(b)) a.ins(*b.begin()), b.ers(b.begin());
}

//初始化;
struct Initializer {
#ifndef DEBUG
  Initializer() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
  }
#else
  ~Initializer() { runtime(); }
#endif
} initializer;

//非标准;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
typedef __gnu_cxx::rope<char> rope;
template <typename key, typename value>
class ext_map
    : public __gnu_pbds::tree<key, value, less<key>, __gnu_pbds::rb_tree_tag,
                              __gnu_pbds::tree_order_statistics_node_update> {};
template <typename key>
class ext_set
    : public __gnu_pbds::tree<key, __gnu_pbds::null_type, less<key>,
                              __gnu_pbds::rb_tree_tag,
                              __gnu_pbds::tree_order_statistics_node_update> {};

struct node {
  int sz;
  int p;
  int val;
  pii max;
  set<pii> q;
};

int main() {
  int n, m, q;
  cin >> n >> m >> q;
  vi p(n);
  cin >> p;
  vpii e(m);
  cin >> e;
  rep(i, m) {
    e[i].x--;
    e[i].y--;
  }
  vi pos(m, q);
  vpii qry;
  rep(i, q) {
    int t, x;
    cin >> t >> x;
    if (t == 1) {
      qry.pb(mp(i, x - 1));
    } else {
      pos[x - 1] = i;
    }
  }
  vi rpos(m);
  rep(i, m) rpos[i] = i;
  sort(all(rpos), [&](int x, int y) { return pos[x] < pos[y]; });
  vec<node> nodes(n);
  rep(i, n) {
    nodes[i].sz = 1;
    nodes[i].p = -1;
    nodes[i].val = p[i];
    nodes[i].max = mp(p[i], i);
  }
  auto find = [&](int x) {
    while (nodes[x].p != -1) {
      x = nodes[x].p;
    }
    return x;
  };
  auto update = [&](int x, bool ers = false, pii e = mp(0, 0)) {
    lp {
      pii old = nodes[x].max;
      pii nw = mp(nodes[x].val, x);
      if (ers) {
        nodes[x].q.ers(e);
      }
      if (sz(nodes[x].q))
        cmax(nw, *nodes[x].q.rbegin());
      // prt(nw);
      // prt(old);
      // prt(x);
      nodes[x].max = nw;
      x = nodes[x].p;
      if (x == -1) {
        break;
      }
      nodes[x].q.ers(old);
      nodes[x].q.ins(nw);
    }
  };
  auto merge = [&](int x, int y) {
    x = find(x), y = find(y);
    if (x == y) {
      return -1;
    }
    if (nodes[x].sz < nodes[y].sz) {
      swap(x, y);
    }
    // prt(mp(x, y));
    nodes[x].p = y;
    nodes[y].sz += nodes[x].sz;
    nodes[y].q.ins(nodes[x].max);
    // prt(nodes[x].max);
    // prt(nodes[y].max);
    // prt(*nodes[y].q.rbegin());
    // prt(y);
    update(y);
    // prt(nodes[x].max);
    // prt(nodes[y].max);
    return x;
  };
  auto unlink = [&](int x) {
    if (x == -1)
      return;
    int y = nodes[x].p;
    nodes[x].p = -1;
    nodes[y].q.erase(nodes[x].max);
    update(y, true, nodes[x].max);
  };
  auto sol = [&](int x) {
    x = find(x);
    int ret = nodes[x].max.x;
    int u = nodes[x].max.y;
    nodes[u].val = 0;
    update(u, true, nodes[x].max);
    return ret;
  };
  vi rt(m);
  rrep(i, m) {
    pii w = e[rpos[i]];
    rt[rpos[i]] = merge(w.x, w.y);
  }
  int j = 0;
  prt(nodes[find(0)].max);
  rep(i, sz(qry)) {
    while (j < m && pos[rpos[j]] < qry[i].x) {
      j++;
      unlink(rt[rpos[j]]);
    }
    prt(i);
    cout << sol(qry[i].y) << endl;
  }
}

#include <bits/stdc++.h>

using namespace std;

template <typename T>
void debug_out(T t) {
  cerr << t;
}

template <typename A, typename B>
void debug_out(pair<A, B> u) {
  cerr << "(" << u.first << " " << u.second << ")";
}

template <typename T>
void debug_out(vector<T> t) {
  int sz = t.size();
  for(int i = 0; i < sz; i++) {
    debug_out(t[i]);
    if(i != sz - 1) cerr << ", ";
  }
}

template <typename T>
void debug_out(vector<vector<T>> t) {
  int sz = t.size();
  for(int i = 0; i < sz; i++) {
    debug_out(t[i]);
    if(i != sz - 1) cerr << endl;
  }
}

template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  debug_out(H);
  cerr << " ";
  debug_out(T...);
}

template <typename T>
void debug_out(set<T> a) {
  vector<T> _a;
  for(T t : a) _a.push_back(t);
  debug_out(_a);
}

#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:" << endl, debug_out(__VA_ARGS__), cerr << endl;

class dsu {
 public:
  vector<int> p;
  int n;
  vector<vector<int>> d;

  dsu(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
    for(int i = 0; i < n; i++) d.push_back({i});
  }

  inline int get(int x) {
    return p[x];
  }

  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if(x == y) return false;
    if(d[x].size() < d[y].size()) swap(x, y);
    for(int i : d[y]) {
      p[i] = x;
      d[x].push_back(i);
    }
    return true;
  }
};

int n, m, q;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> m >> q;
  vector<int> p(n);
  for(int i = 0; i < n; i++) cin >> p[i];
  vector<pair<int, int>> edges;
  for(int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b;
    a--; b--;
    edges.emplace_back(a, b);
  }
  vector<pair<int, int>> que(q);
  vector<int> alive(m, 1);
  for(int i = 0; i < q; i++) {
    int a, b;
    cin >> a >> b;
    b--;
    que[i] = make_pair(a, b);
    if(a == 2) alive[b] = 0;
  }
  dsu d(n);
  for(int i = 0; i < m; i++) if(alive[i]) {
    int a = edges[i].first;
    int b = edges[i].second;
    d.unite(a, b);
  }
  vector<vector<int>> rev(q);
  for(int i = q - 1; i >= 0; i--) {
    int a = que[i].first;
    int b = que[i].second;
    if(a == 2) {
      int u = edges[b].first;
      int v = edges[b].second;
      u = d.get(u);
      v = d.get(v);
      if(u == v) continue;
      rev[i] = d.d[u].size() > d.d[v].size() ? d.d[v] : d.d[u];
      d.unite(u, v);
    }
  }
  d = dsu(n);
  for(int i = 0; i < m; i++) {
    int a = edges[i].first;
    int b = edges[i].second;
    d.unite(a, b);
  }
  vector<set<int>> ret(n);
  vector<int> to(n);
  for(int i = 0; i < n; i++) to[i] = d.get(i);
  for(int i = 0; i < n; i++) ret[to[i]].insert(p[i]);
  vector<int> unused;
  for(int i = 0; i < n; i++) if(ret[i].empty()) unused.push_back(i);
  vector<int> dead(n);
  for(int qs = 0; qs < q; qs++) {
    int x = que[qs].first;
    int y = que[qs].second;
    if(x == 1) {
      y = to[y];
      if(ret[y].empty()) {
        cout << "0\n";
        continue;
      }
      int p = *prev(ret[y].end());
      dead[p - 1] = 1;
      cout << *prev(ret[y].end()) << "\n";
      ret[y].erase(prev(ret[y].end()));
    } else {
      int a = edges[y].first;
      int b = edges[y].second;
      if(rev[y].empty()) continue;
      int id = unused.back();
      unused.pop_back();
      a = to[a];
      for(int i : rev[y]) {
         to[i] = id;
        if(dead[p[i] - 1]) continue;
        ret[a].erase(p[i]);
        ret[id].insert(p[i]);
      }
    }
  }
  return 0;
}

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int n,m,Q;
int fa[600005],u[300005],v[300005];
int getfa(int x){
	if(x!=fa[x])fa[x]=getfa(fa[x]);
	return fa[x];
}
void Merge(int x,int y){
	fa[x]=y;
}
struct Query{
	int type,pos;
}q[500005];
bool usd[300005];
int value[600005],num,valuepos[600005];
struct edge{
	int from,to,nxt;
}e[2000005],ee[600005];
int Head[600005],cnt,cntt,Headd[600005],root[600005],lg[600005];
int depth[600005],f[600005][25];
void add(int x,int y){
	++cnt;
	e[cnt].from=x;
	e[cnt].to=y;
	e[cnt].nxt=Head[x];
	Head[x]=cnt;
}
void addd(int x,int y){
	++cntt;
	ee[cntt].from=x;
	ee[cntt].to=y;
	ee[cntt].nxt=Headd[x];
	Headd[x]=cntt;
}
bool vis[500005];
void dfs(int now,int pre){
	fa[now]=num;
	vis[now]=true;
	add(now,num);
	add(num,now);
	for(int i=Headd[now];i;i=ee[i].nxt){
		int to=ee[i].to;
		if(to==pre||vis[to])continue;
		dfs(to,now);
	}
}
int dfn[500005],sz[500005],tmpcnt,seq[500005];
void dfss(int now,int pre){
	f[now][0]=pre;
	dfn[now]=++tmpcnt;
	seq[tmpcnt]=now;
	sz[now]=1;
	for(int i=1;(1<<i)<=depth[now];++i)f[now][i]=f[f[now][i-1]][i-1];
	for(int i=Head[now];i;i=e[i].nxt){
		if(e[i].to==pre)continue;
		depth[e[i].to]=depth[now]+1;
		dfss(e[i].to,now);
		sz[now]+=sz[e[i].to];
	}
}
int Max[600005<<2];
void build(int l,int r,int rt){
	if(l==r){
		Max[rt]=value[seq[l]];
		return;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void modify(int l,int r,int rt,int pos){
	if(l==r){
		Max[rt]=0;
		return;
	}
	int m=(l+r)>>1;
	if(pos<=m)modify(lson,pos);
	else modify(rson,pos);
	Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
int query(int l,int r,int rt,int nowl,int nowr){
	if(nowl<=l&&r<=nowr)return Max[rt];
	int m=(l+r)>>1,re=0;
	if(m>=nowl)re=max(re,query(lson,nowl,nowr));
	if(m<nowr)re=max(re,query(rson,nowl,nowr));
	return re;
}
void init(){
	for(int i=1;i<=3*n;++i)lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
int lca(int x,int y){
	if(depth[x]<depth[y])swap(x,y);
	while(depth[x]>depth[y])x=f[x][lg[depth[x]-depth[y]]-1];
	if(x==y)return x;
	for(int k=lg[depth[x]]-1;k>=0;--k){
		if(f[x][k]!=f[y][k]){
			x=f[x][k];
			y=f[y][k];
		}
	}
	return f[x][0];
}
int main(){
	scanf("%d%d%d",&n,&m,&Q);
	init();
	for(int i=1;i<=3*n;++i)fa[i]=i;
	for(int i=1;i<=n;++i)scanf("%d",&value[i]),valuepos[value[i]]=i;
	for(int i=1;i<=m;++i)scanf("%d%d",&u[i],&v[i]);
	for(int i=1;i<=Q;++i){
		scanf("%d%d",&q[i].type,&q[i].pos);
		if(q[i].type==2)usd[q[i].pos]=true;
	}
	num=n;
	for(int i=1;i<=m;++i){
		if(!usd[i]){
			addd(u[i],v[i]);
			addd(v[i],u[i]);
		}
	}
	for(int i=1;i<=n;++i){
		if(!vis[i]){
			++num;
			dfs(i,0);
		}
	}
	for(int i=Q;i>=1;--i){
		if(q[i].type==2){
			int r1=getfa(u[q[i].pos]),r2=getfa(v[q[i].pos]);
			if(r1!=r2){
				++num;
				fa[r1]=fa[r2]=num;
				add(r1,num);
				add(r2,num);
				add(num,r1);
				add(num,r2);
			}
		}
		else root[i]=getfa(q[i].pos);
	}
	++num;
	for(int i=1;i<num;++i){
		fa[i]=getfa(i);
		if(fa[i]==i){
			fa[i]=num;
			add(i,num);
			add(num,i);
		}
	}
	dfss(num,0);
	build(1,num,1);
	for(int i=1;i<=Q;++i){
		if(q[i].type==1){
			int ans=query(1,num,1,dfn[root[i]],dfn[root[i]]+sz[root[i]]-1);
			printf("%d\n",ans);
			if(ans)modify(1,num,1,dfn[valuepos[ans]]);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mp make_pair
#define pb push_back
#define VI vector<int>
#define pii pair<int,int>
using namespace std;
const int MAXN = 5e5+10;
int u[MAXN], v[MAXN], per[MAXN];
int su[MAXN], sv[MAXN];
bool rmv[MAXN];
int p[MAXN];
int n, m, q;
int qi[MAXN], val[MAXN], sz[MAXN];
int find(int x){
	if(p[x] == x) return x;
	return p[x] = find(p[x]);
}
void join(int x, int y){
	sz[find(y)] += sz[find(x)];
	p[find(x)] = find(y);
}
bool out[MAXN];
set<int> S[MAXN];
int ss;
int where[MAXN];
vector<pii> g[MAXN];
bool V[MAXN];
void dfs(int cur, int prev, int to){
	V[cur] = true;
	where[cur] = to;
	S[to].insert(cur);
	for(int i = 0; i < (int)g[cur].size(); i++){
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs(next, cur, to);
	}
}
void dfs1(int cur, int prev, int from, int to){
	S[from].erase(cur);
	if(!out[cur]) S[to].insert(cur);
	else S[to].insert(0);
	where[cur] = to;
	for(int i = 0; i < (int)g[cur].size(); i++){
		if(rmv[g[cur][i].second]) continue;
		int next = g[cur][i].first;
		if(next == prev) continue;
		dfs1(next, cur, from, to);
	}
}
int main(){
	scanf("%d %d %d", &n, &m, &q);
	for(int i = 1; i <= n; i++){
		scanf("%d", &per[i]);
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= m; i++){
		scanf("%d %d", &u[i], &v[i]);
		u[i] = per[u[i]];
		v[i] = per[v[i]];
	}
	for(int i = 0; i < q; i++){
		scanf("%d %d", &qi[i], &val[i]);
		if(qi[i] == 2) rmv[val[i]] = true;
		else val[i] = per[val[i]];
	}
	for(int i = 1; i <= m; i++){
		if(rmv[i]) continue;
		join(u[i], v[i]);
	}
	for(int i = q-1; i >= 0; i--){
		if(qi[i] == 2){
			//ru[i] = find(u[val[i]]);
			//rv[i] = find(v[val[i]]);
			int x = u[val[i]], y = v[val[i]];
			if(find(x) == find(y)){
				su[i] = sv[i] = -1;
				continue;
			}
			su[i] = sz[find(x)];
			sv[i] = sz[find(y)];
			g[x].pb(mp(y,val[i]));
			g[y].pb(mp(x,val[i]));
			join(x, y);

		}
	}
	for(int i = 1; i <= n; i++){
		p[i] = i; sz[i] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 0; j < (int)g[i].size(); j++){
			int x = i, y = g[i][j].first;
			join(x, y);
		}
	}
	for(int i = 1; i <= m; i++){
		int x = u[i], y = v[i];
		if(find(x) == find(y)) continue;
		g[x].pb(mp(y,i)); g[y].pb(mp(x,i));
		join(x, y);
	}
	ss = 0;
	memset(V, false, sizeof V);
	for(int i = 1; i <= n; i++){
		if(!V[i]) dfs(i, i, ss++);
	}
	for(int i = 1; i <= m; i++) rmv[i] = false;
	for(int i = 0; i < q; i++){
		if(qi[i] == 1){
			int cur = val[i];
			int w = where[cur];
			int ans = *S[w].rbegin();
			printf("%d\n", ans);
			if(ans){
				out[ans] = true;
				S[w].erase(ans);
				S[w].insert(0);
			}
		}else{
			rmv[val[i]] = true;
			if(su[i] == -1) continue;
			int ei = val[i];
			if(su[i] < sv[i]){
				dfs1(u[ei], u[ei], where[u[ei]], ss++);
			}else{
				dfs1(v[ei], v[ei], where[v[ei]], ss++);
			}
		}
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define per(i, a, b) for(int i = b-1; i>=a ; i--)
#define trav(a, x) for(auto& a : x)
#define allin(a , x) for(auto a : x)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<ll> vl;
typedef vector<pii> vpi;
typedef pair<ll,ll> pll;
typedef vector<string> vs;
typedef vector<pll> vpl;
typedef vector<int> vi;

const int N = 500005;

int p[N] , n, m,q,pai[N],peso[N];
set<int> comp[N];
map<int, vi> fromsmall[N];
struct snapshot{
	int psx, psy, x,y;
};
vector<snapshot> torb;
int fd(int x){
	return pai[x] == x ? x : fd(pai[x]);
}
bool join(int u , int v){
	u = fd(u) , v = fd(v);
	if(u == v)
		return false;
	if(peso[u] > peso[v])
		swap(u,v);
	torb.push_back({peso[u] , peso[v] , u , v});
	pai[u] = v, peso[v] += peso[u];
	for(auto w : comp[u])
		comp[v].insert(w) , fromsmall[v][u].push_back(w);
	comp[u].clear();
	return true;
}
void rollback(){
	if(sz(torb)){
		auto u = torb.back();
		torb.pop_back();
		pai[u.x] = u.x , pai[u.y] = u.y;
		peso[u.y] -= peso[u.x];
		for(auto w : fromsmall[u.y][u.x]){
			if(comp[u.y].count(w)){
				comp[u.y].erase(w);
				comp[u.x].insert(w);
			}
		}
		fromsmall[u.y].erase(u.x);
	}
}
pii edge[N];
struct querys{
	int a , b , mark = 0;
} Q[N];
set<int> curr;
int rev[N];
int32_t main(){
	scanf("%d%d%d" , &n, &m , &q);
	rep(i,1,n+1)
		scanf("%d" , &p[i]) , rev[p[i]] = i;
	rep(i,1,m+1)
		scanf("%d%d" , &edge[i].F , &edge[i].S) , curr.insert(i);
	rep(i,1,q+1){
		scanf("%d%d" , &Q[i].a,  &Q[i].b);
		if(Q[i].a == 2){
			curr.erase(Q[i].b);
		}
	}
	for(auto w : curr){
		Q[++q] = {2,w};
	}
	rep(i,1,n+1){
		pai[i] = i , peso[i] = 1 , comp[i].insert(p[i]);
	}
	per(i,1,q+1){
		if(Q[i].a == 2){
			if(join(edge[Q[i].b].F , edge[Q[i].b].S))
				Q[i].mark = 1;
		}
	}
	rep(i,1,q+1){
		if(Q[i].a == 1){
			int ff = fd(Q[i].b);
			if(sz(comp[ff])){
				auto best = *prev(end(comp[ff]));
				comp[ff].erase(best);
				printf("%d\n" , best);
			}
			else{
				printf("%d\n" , 0);
			}
		}
		else{
			if(Q[i].mark)
				rollback();
		}
	}
}

#include <bits/stdc++.h>
#define int long long
using namespace std;

#define mp make_pair
#define mt make_tuple
#define pb push_back
#define ms(v, x) memset((v), (x), sizeof(v))
#define all(v) (v).begin(), (v).end()
#define ff first
#define ss second
#define iopt ios::sync_with_stdio(false); cin.tie(0)

int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
int power(int x, int p, int MOD) {
    if(p == 0) return 1%MOD;
    if(p == 1) return x%MOD;
    int res = power(x, p/2, MOD);
    res = (long long)res*res%MOD;
    if(p&1) res = (long long)res*x%MOD;
    return res;
}

typedef pair<int, int> ii;
typedef long double LD;
typedef vector<int> vi;

const int N = 200010;
const int M = 500005;

struct Query {
    int type, id;
};

int no_inv[N], label[N];
int root(int u) {
    return no_inv[u];
}

struct Node;
int node_ptr = 0;
Node *no;

struct Node {
    vector<int> m;
    int child = -1;
    int poll(int id) {
        int res = 0;
        while(!m.empty()) {
            int u = m.back();
            m.pop_back();
            if(no_inv[u] == id && label[u]) {
                res = label[u];
                label[u] = 0;
                break;
            }
        }
        return res;
    }
    void split() {
        for(int x : no[child].m) {
            no_inv[x] = child;
        }
    }
};

int make_node() {
    return node_ptr++;
}

ii ed[M];
bool deleted[M];
Query qrs[M];
int ans[M];

// before
vector<int> adj[N];
bool vis[N];
int dfs_node;
void dfs(int u) {
    if(vis[u]) return;
    vis[u] = 1;
    no[dfs_node].m.pb(u);
    no_inv[u] = dfs_node;
    for(int v : adj[u])
        dfs(v);
}

int32_t main(){
    iopt;
    int n, m, q;
    cin >> n >> m >> q;
    no = new Node[N];

    for(int i = 0; i < n; i++) {
        cin >> label[i];
    }

    for(int i = 0; i < m; i++) {
        cin >> ed[i].ff >> ed[i].ss;
        ed[i].ff--, ed[i].ss--;
    }

    for(int i = 0; i < q; i++) {
        cin >> qrs[i].type >> qrs[i].id;
        qrs[i].id--;
        if(qrs[i].type == 2)
            deleted[qrs[i].id] = true;
    }

    for(int i = 0; i < m; i++) {
        if(!deleted[i]) {
            adj[ed[i].ff].pb(ed[i].ss);
            adj[ed[i].ss].pb(ed[i].ff);
        }
    }

    for(int i = 0; i < n; i++) {
        if(!vis[i]) {
            dfs_node = make_node();
            dfs(i);
        }
    }

    memset(deleted, 0, sizeof deleted);

    for(int i = q-1; i >= 0; i--) {
        if(qrs[i].type == 2) {
            ii& e = ed[qrs[i].id];
            int a = root(e.ff), b = root(e.ss);
            if(a != b) {
                // merge
                int m_no = make_node();
                if(no[a].m.size() < no[b].m.size()) swap(a, b);
                no[a].child = b;
                copy(all(no[b].m), back_inserter(no[a].m));
                for(int x : no[b].m) no_inv[x] = a;
                deleted[qrs[i].id] = true;
            }
        }
    }

    for(int i = 0; i < node_ptr; i++) {
        sort(all(no[i].m), [](int a, int b) {
            return label[a] < label[b];
        });
    }

    for(int i = 0; i < q; i++) {
        if(qrs[i].type == 1) {
            int u = qrs[i].id;
            u = root(u);
            cout << no[u].poll(u) << "\n";
        } else if(deleted[qrs[i].id]) {
            int u = root(ed[qrs[i].id].ff);
            assert(no[u].child != -1);
            no[u].split();
        }
    }
}

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 5e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

struct node
{
	int id, w;
	bool operator < (const node &oth) const {
		return w > oth.w;
	}
};
struct Ask
{
	int op, x;
}qi[N];
pir eg[N];
set <node> s[N];
int fa[N], sz[N], n, m, q;
int a[N];
bool vis[N];
stack <pir> st;

void Init() {
	for (int i = 1; i <= n; i++)
		fa[i] = i, sz[i] = 1;
}
int Find(int x) {
	while (x != fa[x])
		x = fa[x];
	return x;
}
void Merge(int x, int y) {
	x = Find(x);
	y = Find(y);
	if (x == y) {
		st.push({ 0, 0 });
		return;
	}
	if (sz[x] > sz[y])
		swap(x, y);
	fa[x] = y;
	st.push({ x, y });
	sz[y] += sz[x];
	for (auto it : s[x])
		s[y].insert(it);
}
void Cancle() {
	int x = st.top().first, y = st.top().second;
	st.pop();
	if (!x && !y)
		return;
	fa[x] = x;
	sz[y] -= sz[x];
	for (auto it : s[x]) {
		auto v = it;
		if (s[y].find(v) != s[y].end())
			s[y].erase(v);
	}
}

int main()
{
	cin >> n >> m >> q;
	Init();
	for (int i = 1; i <= n; i++)
		sc("%d", &a[i]), s[i].insert({ i, a[i] });
	for (int i = 1; i <= m; i++)
		sc("%d %d", &eg[i].first, &eg[i].second);
	for (int i = 1; i <= q; i++) {
		sc("%d %d", &qi[i].op, &qi[i].x);
		if (qi[i].op == 2)
			vis[qi[i].x] = true;
	}
	for (int i = 1; i <= m; i++)
		if (!vis[i])
			Merge(eg[i].first, eg[i].second);
	for (int i = q; i >= 1; i--) {
		if (qi[i].op == 1)
			continue;
		int u = eg[qi[i].x].first;
		int v = eg[qi[i].x].second;
		Merge(u, v);
	}

	for (int i = 1; i <= q; i++) {
		int op = qi[i].op, x = qi[i].x;
		if (op == 1) {
			int u = Find(x);
			if (s[u].empty()) {
				printf("%d\n", a[u]);
				a[u] = 0;
				continue;
			}
			int v = s[u].begin()->id;
			printf("%d\n", s[u].begin()->w);
			s[u].erase({ v, a[v] });
			a[v] = 0;
			s[u].insert({ v, a[v] });
		}
		else
			Cancle();
	}
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

/*
	Name:
	Author: Gensokyo_Alice
	Date:
	Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, Q, val[MAXN], id[MAXN], tag[MAXN], fa[MAXN], vis[MAXN];
ll ed[MAXN], be[MAXN], a[MAXN], num;
struct ed {
	ll x, y;
} e[MAXN];
struct opt {
	ll kind, k;
} o[MAXN];
struct edge {
	ll nt, to;
} E[MAXN];
struct lk {
	ll pre, nxt;
} t[MAXN];
struct nod {
	ll l, r, maxn, pos;
} tr[MAXN];
struct ww {
	ll l, r;
} kk[MAXN];

ll find_(ll);
ll ask(ll, ll, ll);
void ins(ll, ll);
void build(ll, ll, ll);
void updata(ll);
void dfs(ll, ll);

int main() {
	scanf("%lld%lld%lld", &N, &M, &Q);
	for (ll i = 1; i <= N; i++) scanf("%lld", a+i), fa[i] = i, ed[i] = i, be[i] = i;
	for (ll i = 1; i <= M; i++) scanf("%lld%lld", &e[i].x, &e[i].y);
	for (ll i = 1; i <= Q; i++) {
		scanf("%lld%lld", &o[i].kind, &o[i].k);
		if (o[i].kind == 2) tag[o[i].k] = 1;
	}
	for (ll i = 1; i <= M; i++) {
		if (!tag[i]) {
			ll fx = find_(e[i].x), fy = find_(e[i].y);
			if (fx != fy) {
				fa[fx] = fy;
				t[ed[fx]].nxt = be[fy];
				t[be[fy]].pre = ed[fx];
				be[fy] = be[fx];
			}
		}
	}
	for (ll i = Q; i; i--) {
		if (o[i].kind == 2) {
			ll tmp = o[i].k;
			ll fx = find_(e[tmp].x), fy = find_(e[tmp].y);
			if (fx == fy) {
				tag[tmp] = 0;
			} else {
				fa[fx] = fy;
				t[ed[fx]].nxt = be[fy];
				t[be[fy]].pre = ed[fx];
				be[fy] = be[fx];
				// onion
			}
		} else {
			ll x = find_(o[i].k);
			kk[i].l = be[x];
			kk[i].r = ed[x];
		}
	}
	for (ll i = 1; i <= N; i++) if (!t[i].pre) dfs(i, 0);
	build(1, 1, num);
	for (ll i = 1; i <= Q; i++) {
		if (o[i].kind == 1) {
			ll tem;
			printf("%lld\n", val[tem = ask(1, id[kk[i].l], id[kk[i].r])]);
			ins(1, tem);
		}
	}
    return 0;
}

ll ask(ll node, ll a, ll b) {
	if (a <= tr[node].l && tr[node].r <= b) return tr[node].pos;
	ll mid = (tr[node].l + tr[node].r) >> 1, ret = 0;
	if (a <= mid) {
		ll tem = ask(node << 1, a, b);
		if (val[tem] > val[ret]) ret = tem;
	}
	if (mid < b) {
		ll tem = ask(node << 1 | 1, a, b);
		if (val[tem] > val[ret]) ret = tem;
	}
	return ret;
}

void ins(ll node, ll pos) {
	if (tr[node].l == pos && tr[node].r == pos) {
		tr[node].maxn = 0;
		val[tr[node].pos] = 0;
		return;
	}
	ll mid = (tr[node].l + tr[node].r) >> 1;
	if (pos <= mid) ins(node << 1, pos);
	else ins(node << 1 | 1, pos);
	updata(node);
}

void build(ll node, ll l, ll r) {
	tr[node].l = l;
	tr[node].r = r;
	tr[node].maxn = 0;
	tr[node].pos = 0;
	if (l == r) {
		tr[node].maxn = val[l];
		tr[node].pos = l;
		return;
	}
	ll mid = (l + r) >> 1;
	build(node << 1, l, mid);
	build(node << 1 | 1, mid + 1, r);
	updata(node);
}

void updata(ll node) {
	if (tr[node << 1 | 1].maxn > tr[node << 1].maxn) {
		tr[node].maxn = tr[node << 1 | 1].maxn;
		tr[node].pos = tr[node << 1 | 1].pos;
	} else {
		tr[node].maxn = tr[node << 1].maxn;
		tr[node].pos = tr[node << 1].pos;
	}
}

void dfs(ll n, ll ff) {
	vis[n] = 1, id[n] = ++num, val[num] = a[n];
	if (t[n].nxt && !vis[t[n].nxt]) dfs(t[n].nxt, n) ;
}

ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
//#pragma GCC optimize("O3")
//#pragma GCC target("sse4")
//#pragma GCC target("avx2")

#define deb(x) cout << #x << " = " << x << "\n"
#define all(x) (x).begin(), (x).end()
#define len(x) (int) x.size()
#define lsb(x) (x) & -(x)
#define l(x) (x << 1) + 1
#define r(x) (x << 1) + 2
#define v(x) (int)(x - 'a')

#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ld, ld> pld;
typedef pair <ll, ll> pll;

template <class T1, class T2 = less <T1>> using pb_heap = __gnu_pbds::priority_queue <T1, T2, binary_heap_tag>;
template <class T1, class T2 = null_type, class T3 = less <T1>> using pb_map = tree <T1, T2, T3, rb_tree_tag, tree_order_statistics_node_update>;
template <class T1, class T2 = null_type, class T3 = hash <T1>> using pb_umap = gp_hash_table <T1, T2, T3>;
template <class T1, class T2, class T3 = hash <T1>> using umap = unordered_map <T1, T2, T3>;
template <class T> using uset = unordered_set <T>;
template <class T> using vec = vector <T>;

const ll infll = numeric_limits <ll>::max() >> 1;
const int inf = numeric_limits <int>::max() >> 1;
const int N = 5e5 + 1;
int n, m, q, curr;
int arr[N];
int ind[N];

bool vis[N];

pii qry[N];
pii edge[N];

vec <int> roots;

struct Graph {
    int lef[N];
    int rig[N];
    vec <int> adj[N];
} graph;

struct Node {
    int l, r;
    pii mxm;
} node[N << 2];

struct Dsu {
    int par[N];
} dsu;

int root(int u) {
    return dsu.par[u] == u? u: dsu.par[u] = root(dsu.par[u]);
}

void unite(int u, int v) {
    u = root(u);
    v = root(v);
    int p = ++n;
    graph.adj[p].pb(u);
    graph.adj[p].pb(v);
    dsu.par[p] = p;
    dsu.par[u] = p;
    dsu.par[v] = p;
}

void merge(int id, int l, int r) {
    node[id].mxm = max(node[l].mxm, node[r].mxm);
}

void build(int id, int l, int r) {
    node[id].l = l;
    node[id].r = r;
    if(l == r) {
        node[id].mxm.xx = arr[ind[l]];
        node[id].mxm.yy = l;
        return;
    }
    int q = l + r >> 1;
    build(l(id), l, q);
    build(r(id), q + 1, r);
    merge(id, l(id), r(id));
}

void erase(int id, int i) {
    if(node[id].l == node[id].r) {
        node[id].mxm.xx = 0;
        return;
    }
    int q = node[id].l + node[id].r >> 1;
    if(i <= q) {
        erase(l(id), i);
    } else {
        erase(r(id), i);
    }
    merge(id, l(id), r(id));
}

pii query(int id, int l, int r) {
    if(node[id].l == l && node[id].r == r) {
        return node[id].mxm;
    }
    pii res = {0, 0};
    int q = node[id].l + node[id].r >> 1;
    if(l <= q) {
        res = max(res, query(l(id), l, min(q, r)));
    }
    if(r > q) {
        res = max(res, query(r(id), max(q + 1, l), r));
    }
    return res;
}

void dfs(int u) {
    static int t = 0;
    ind[++t] = u;
    graph.lef[u] = t;
    for(int v: graph.adj[u]) {
        dfs(v);
    }
    graph.rig[u] = t;
}

void input() {
    cin >> n >> m >> q;
    for(int i = 1; i <= n; ++i) {
        cin >> arr[i];
    }
    for(int i = 1; i <= m; ++i) {
        int u; cin >> u;
        int v; cin >> v;
        edge[i] = {u, v};
    }
    for(int i = 1; i <= q; ++i) {
        cin >> qry[i].xx;
        cin >> qry[i].yy;
        if(qry[i].xx == 2) {
            vis[qry[i].yy] = 1;
        }
    }
}

void solve() {
    for(int i = 1; i <= n; ++i) {
        dsu.par[i] = i;
    }
    for(int i = 1; i <= m; ++i) {
        if(!vis[i]) {
            int u = edge[i].xx;
            int v = edge[i].yy;
            unite(u, v);
        }
    }
    for(int i = q; i >= 1; --i) {
        if(qry[i].xx == 1) {
            roots.pb(root(qry[i].yy));
        } else {
            int u = edge[qry[i].yy].xx;
            int v = edge[qry[i].yy].yy;
            if(root(u) == root(v)) {
                continue;
            }
            unite(u, v);
        }
    }
    for(int i = 1; i <= n; ++i) {
        if(root(i) == i) {
            dfs(i);
        }
    }
    build(0, 1, n);
    reverse(all(roots));
    if(n > 100) {
        cout << n << " <<\n";
        return;
    }
    for(int e: roots) {
        pii p = query(0, graph.lef[e], graph.rig[e]);
        erase(0, p.yy);
        cout << p.xx << "\n";
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    input();
    solve();
}

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>

template <typename Tp> void read(Tp &res){
	static char ch; ch = getchar(), res = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) res = res * 10 + ch - 48, ch = getchar();
}

const int MAXN = 2e5 + 19, MAXM = 3e5 + 19;

int n, m, q, fa[MAXN], birth[MAXM], p[MAXN], opt[MAXN], arg[MAXN];
int getf(int node){return node == fa[node] ? node : fa[node] = getf(fa[node]);}
std::vector<int> mt[MAXN];
std::pair<int, int> G[MAXM];
bool vist[MAXN];

int main(){
	read(n), read(m), read(q);
	for(int i = 1; i <= n; ++i) read(p[i]), fa[i] = i, mt[i].push_back(i);
	for(int i = 1; i <= m; ++i) read(G[i].first), read(G[i].second);
	for(int i = 1; i <= q; ++i){
		read(opt[i]), read(arg[i]);
		if(opt[i] == 2) vist[arg[i]] = 1;
	}
	for(int i = 1; i <= m; ++i){
		int a = G[i].first, b = G[i].second;
		a = getf(a), b = getf(b);
		if(vist[i] || a == b) continue;
		birth[i] = b;
		for(int j : mt[b]) mt[a].push_back(j);
		fa[b] = a;
	}
	for(int i = q; i >= 1; --i)
		if(opt[i] == 2){
			int a = G[arg[i]].first, b = G[arg[i]].second;
			a = getf(a), b = getf(b);
			if(a == b) continue;
			birth[arg[i]] = b;
			for(int j : mt[b]) mt[a].push_back(j);
			fa[b] = a;
		}
	for(int i = 1; i <= n; ++i) std::sort(mt[i].begin(), mt[i].end(), [](const int &a, const int &b){return p[a] < p[b];});
	for(int i = 1; i <= q; ++i){
		if(opt[i] == 1){
			int a = getf(arg[i]);
			while(!mt[a].empty() && getf(mt[a].back()) != a) mt[a].pop_back();
			if(mt[a].empty()) puts("0");
			else printf("%d\n", p[mt[a].back()]), fa[mt[a].back()] = 0;
		}
		else{
			int a = birth[arg[i]];
			for(int j : mt[a]) if(fa[j]) fa[j] = a;
		}
	}
	return 0;
}

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#define maxn 300005
#define lson (now<<1)
#define rson ((now<<1)|1)
#define mid ((nl+nr)>>1)
using namespace std;
typedef long long ll;
int n,m,q;
int a[maxn];
int vis[maxn];
int u[maxn],v[maxn];
int op[maxn],val[maxn];
int fa[maxn],id[maxn];
int getfa(int now)
{
	return fa[now]==now ? now : fa[now]=getfa(fa[now]);
}
int tot,cnt=n;
int to[maxn<<2],nex[maxn<<2],head[maxn<<1];
void add(int x,int y)
{
	to[++tot]=y;  nex[tot]=head[x]; head[x]=tot;
}
int l[maxn<<1],r[maxn<<1],dfn[maxn<<1];
int dat1[maxn<<3],dat2[maxn<<3];
void pushup(int now)
{
	if(dat1[lson]<dat1[rson])
		dat1[now]=dat1[rson],dat2[now]=dat2[rson];
	else
		dat1[now]=dat1[lson],dat2[now]=dat2[lson];
}
void update(int ql,int val,int nl,int nr,int now)
{
	if(nl==nr)
	{
		dat1[now]=val;
		dat2[now]=nl;
		return;
	}
	if(ql<=mid)
		update(ql,val,nl,mid,lson);
	else
		update(ql,val,mid+1,nr,rson);
	pushup(now);
}
void dfs(int now,int fa)
{
	vis[now]=1;
	dfn[now]=++tot;
	l[now]=tot;

	if(now<=n)
		update(tot,a[now],1,cnt,1);

	for(int i=head[now];i;i=nex[i])
	if(to[i]!=fa)
		dfs(to[i],now);
	r[now]=tot;
}
pair<int,int> query(int ql,int qr,int nl,int nr,int now)
{
	if(ql<=nl && nr<=qr)
		return {dat1[now],dat2[now]};
	pair<int,int> ans={-1,-1};
	if(ql<=mid)
		ans=max(ans,query(ql,qr,nl,mid,lson));
	if(mid<qr)
		ans=max(ans,query(ql,qr,mid+1,nr,rson));
	return ans;
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),fa[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d",&u[i],&v[i]);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&op[i],&val[i]);
		if(op[i]==2)
			vis[val[i]]=1;
	}

	for(int i=1;i<=m;i++)
	if(!vis[i])
	{
		int xx=getfa(u[i]),yy=getfa(v[i]);
		if(xx!=yy)
		{
			fa[xx]=yy;
			add(u[i],v[i]);
			add(v[i],u[i]);
		}
	}

	cnt=n;

	for(int i=q;i>=1;i--)
	{
		if(op[i]==1)//精髓
			val[i]=getfa(val[i]);
		else
		{
			int xx=getfa(u[i]),yy=getfa(v[i]);
			if(xx!=yy)
			{
				cnt++;
				fa[xx]=cnt;
				fa[yy]=cnt;
				fa[cnt]=cnt;
				add(cnt,xx);
				add(cnt,yy);
			}
		}
	}
	memset(vis,0,sizeof(vis));

	tot=0;
	for(int i=1;i<=n;i++)
		if(!vis[getfa(i)])
			dfs(getfa(i),-1);

	for(int i=1;i<=q;i++)
	{
		if(op[i]==1)
		{
			pair<int,int> res=query(l[val[i]],r[val[i]],1,cnt,1);
			printf("%d\n",res.first);
			update(res.second,0,1,cnt,1);
		}
	}
}

#include <bits/stdc++.h>

#define f first
#define s second
#define pb push_back
#define mp make_pair

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;

const int N = (int)5e5 + 123, inf = 1e9, mod = 1e9 + 7;
const ll INF = 1e18;

int n, m, q, k, a[N], b[N], type[N], val[N], ans[N], lim[N];
int p[N], sz[N];
set < pii > st[N];
bool skip[N], del[N], used[N];
pii t[N];
vector< int > vec[N];

int get(int v){
	if(p[v] == v)
		return v;
	return get(p[v]);
}
void Merge(int i){
	//cerr << i << " " ;
	if(used[i]){
	//	cerr << "- " << a[i] << " " << b[i] << " ";
		if(skip[i]){
	//		cerr << "skip";
			skip[i] = 0;
		}else{
			k--;
			int v = t[k].f;
			int u = t[k].s;
			for(auto it : st[u])
				st[v].erase(it);
			sz[v] -= sz[u];
			p[u] = u;
		}
	}else{
	//	cerr << "+ " << a[i] << " " << b[i] << " ";
		int v = get(a[i]);
		int u = get(b[i]);
		if(v == u){
	//		cerr << "skip";
			skip[i] = 1;
		}else{
			if(sz[v] < sz[u])
				swap(v, u);
			for(auto it : st[u])
				if(!del[it.s])
					st[v].insert(it);
			sz[v] += sz[u];
			p[u] = v;
			t[k++] = {v, u};
		}
	}
	//cerr << endl;
	used[i] ^= 1;
}
void fix(int v){
	while(!st[v].empty()){
		int i = st[v].begin() -> s;
		if(del[i])
			st[v].erase(st[v].begin());
		else
			break;
	}
}
int main()
{
	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", &a[i], &b[i]);
	for(int i = 1; i <= q; i++)
		scanf("%d%d", &type[i], &val[i]);
	for(int i = 1; i <= m; i++)
		lim[i] = q + 1;
	for(int i = 1; i <= q; i++)
		if(type[i] == 2)
			lim[val[i]] = i;
	for(int i = 1; i <= m; i++)
		vec[val[i]].pb(i);
	for(int i = 1; i <= n; i++){
		st[i].insert({n - p[i], i});
		p[i] = i, sz[i] = 1;
	}
	for(int i = q + 1; i >= 1; i--)
		for(auto j : vec[i])
			Merge(j);
	for(int i = 1; i <= q; i++){
	    reverse(vec[i].begin(), vec[i].end());
		for(auto j : vec[i])
			Merge(j);
		if(type[i] != 1)
			continue;
		int v = val[i];
		v = get(v);
		fix(v);
		if(st[v].empty()){
			ans[i] = 0;
			printf("0\n");
		}else{
			ans[i] = st[v].begin() -> f;
			printf("%d\n", n - ans[i]);
			del[st[v].begin() -> s] = 1;
		}
	}
}

#include<algorithm>
#include<cstdio>
#include<vector>
#define pb push_back
#define MaxN 200500
using namespace std;
vector<int> p[MaxN];
int f[MaxN],c[MaxN];
int find(int u)
{return f[u]==u ? u : find(f[u]);}
void merge(int &u,int &v)
{
  u=find(u);v=find(v);
  if (u==v)return ;
  if (c[v]>c[u])swap(u,v);
  c[f[u]=v]+=c[u];
  for (int j=0;j<p[u].size();j++)
    p[v].pb(p[u][j]);
}
int w[MaxN],top[MaxN];
bool del[300500];
int qry(int u)
{
  while(p[u].size()&&(del[p[u].back()]||top[p[u].back()]!=u))
    p[u].pop_back();
  if (p[u].empty())return 0;
  int ret=p[u].back();
  del[ret]=1;
  return ret;
}
struct Data{int op,x;}b[500500];
struct Line{int u,v;}l[300500];
int n,m,q;
int main()
{
  scanf("%d%d%d",&n,&m,&q);
  for (int i=1;i<=n;i++){
    scanf("%d",&w[i]);
    p[i].pb(w[i]);
    c[f[i]=i]=1;
  }
  for (int i=1;i<=m;i++)
    scanf("%d%d",&l[i].u,&l[i].v);
  for (int i=1;i<=q;i++){
    scanf("%d%d",&b[i].op,&b[i].x);
    if (b[i].op==2)del[b[i].x]=1;
  }
  for (int i=1;i<=m;i++){
    if (del[i])continue ;
    merge(l[i].u,l[i].v);
  }
  for (int i=q;i;i--)
    if (b[i].op==2)
      merge(l[i].u,l[i].v);
  for (int i=1;i<=n;i++){
    sort(p[i].begin(),p[i].end());
    del[i]=0;top[w[i]]=find(i);
  }
  for (int i=1;i<=q;i++){
  	if (b[i].op==1)
      printf("%d\n",qry(find(b[i].x)));
  	else {
  	  if (l[i].u==l[i].v)continue;
  	  int u=l[i].u;
  	  for (int j=0;j<p[u].size();j++)
        top[p[u][j]]=u;
      f[u]=u;
  	}
  }return 0;
}

#pragma region Macros
#pragma GCC optimize("O3")
#pragma GCC target("avx2,avx")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define rep2(i, a, b) for(ll i = a; i <= b; ++i)
#define rep(i, n) for(ll i = 0; i < n; ++i)
#define rep3(i, a, b) for(ll i = a; i >= b; --i)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define vll vector<ll>
#define vpi vector<pii>
#define vpll vector<pll>
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size)                                                                                \
    vector<type> name(size);                                                                                \
    IN(name)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w)                                                                                \
    vector<vector<type>> name(h, vector<type>(w));                                                                                \
    IN(name)
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define fi first
#define se second
#define all(c) begin(c), end(c)
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
using namespace std;
string YES[2] = {"NO", "YES"};
string Yes[2] = {"No", "Yes"};
string yes[2] = {"no", "yes"};
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
#define si(c) (int)(c).size()
#define INT(...)                                                                                \
    int __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define LL(...)                                                                                \
    ll __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define STR(...)                                                                                \
    string __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                \
    char __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                \
    double __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &... tail) {
    scan(head);
    IN(tail...);
}
template <class T, class S> inline bool chmax(T &a, S b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T, class S> inline bool chmin(T &a, S b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
vi iota(int n) {
    vi a(n);
    iota(all(a), 0);
    return a;
}
template <typename T> vi iota(vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(all(res), 0);
    sort(all(res), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    sort(all(y));
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
int popcount(ll x) { return __builtin_popcountll(x); }
struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(15);
    }
} setup_io;
int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return move(res);
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        cin >> a >> b >> c;
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return move(res);
}

#define i128 __int128_t
#define ull unsigned long long int
#define TEST                                                                                \
    INT(testcases);                                                                                \
    while(testcases--)
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    for(auto &e : v) cout << e << " ";
    cout << endl;
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    cout << "(" << p.fi << ", " << p.se << ")";
    return os;
}
template <class S, class T> string to_string(pair<S, T> p) { return "(" + to_string(p.first) + "," + to_string(p.second) + ")"; }
template <class A> string to_string(A v) {
    if(v.empty()) return "{}";
    string ret = "{";
    for(auto &x : v) ret += to_string(x) + ",";
    ret.back() = '}';
    return ret;
}

void dump() { cerr << endl; }
template <class Head, class... Tail> void dump(Head head, Tail... tail) {
    cerr << to_string(head) << " ";
    dump(tail...);
}
#define endl '\n'
#ifdef _LOCAL
#undef endl
#define debug(x)                                                                                \
    cout << #x << ": ";                                                                                \
    dump(x)
#else
#define debug(x)
#endif
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

// int rnd(int n) { return uniform_int_distribution<int>(0, n - 1)(rng); }
// ll rndll(ll n) { return uniform_int_distribution<ll>(0, n - 1)(rng); }

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
#pragma endregion

vector<int> a;
template <typename T = int> struct UnionFind {
    vector<int> data;
    vector<set<int>> s;
    struct A {
        int x, y, datx, daty;
        A() = default;
    };
    vector<A> hist;
    int num;

    UnionFind(int n) : num(n) {
        data.assign(n, -1);
        s.resize(n);
        rep(i, n) s[i].emplace(a[i]);
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if(x == y) {
            A a;
            a.y = -1;
            hist.eb(a);
            return false;
        }
        num--;
        if(data[x] > data[y]) swap(x, y);
        hist.eb(A{x, y, data[x], data[y]});
        data[x] += data[y];
        data[y] = x;
        for(auto &e : s[y]) s[x].emplace(e);
        return true;
    }

    int find(int x) {
        if(data[x] < 0) return x;
        return (data[x] = find(data[x]));
    }

    void undo() {
        auto &a = hist.back();
        hist.pop_back();
        if(a.y == -1) { return; }
        int x = a.x, y = a.y;
        data[x] = a.datx;
        data[y] = a.daty;
        for(auto it = s[y].begin(); it != s[y].end();) {
            auto it2 = s[x].find(*it);
            if(it2 != s[x].end())
                s[x].erase(it2), it++;
            else
                it = s[y].erase(it);
        }
    }
    int get(int x) {
        x = find(x);
        if(s[x].empty())
            return 0;
        else {
            int res = *s[x].rbegin();
            s[x].erase(--s[x].end());
            return res;
        }
    }
};

int main() {
    INT(n, m, q);
    a.resize(n);
    rep(i, n) cin >> a[i];
    vector<pii> E;
    rep(i, m) {
        INT(x, y);
        x--, y--;
        E.eb(x, y);
    }
    vi used(m);
    vi edges;
    vector<pii> query;
    rep(i, q) {
        INT(t, s);
        query.eb(t, --s);
        if(t == 2) {
            edges.eb(s);
            used[s] = true;
        }
    }
    rep(i, m) if(!used[i]) edges.eb(i);
    UnionFind uf(n);
    reverse(all(edges));
    for(auto i : edges) uf.unite(E[i].fi, E[i].se);
    for(auto [t, s] : query) {
        if(t == 1) {
            int res = uf.get(s);
            if(s == 4 and n == 95) {
                dump(uf.s[uf.find(s)]);
                exit(0);
            }
            cout << res << endl;
        } else
            uf.undo();
    }
}

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,r,l) for(int i=(r);i>=(l);--i)
#define For(i,u) for(int i=hed[u],v=e[i].to;i;i=e[i].nex,v=e[i].to)
#define fi first
#define se second
#define mp make_pair
using namespace std;
const int N=2e5+10;
int f[N],sz[N],hed[N],ed,n,m,Q,id[N],opt[N],a[N],u[N],v[N],del[N];
set<pair<int,int> > s[N];bool ban[N];
struct edge{
	int to,nex;bool vis;
	edge(int _=0,int __=0):to(_),nex(__),vis(0){}
}e[N<<1];
inline void add(int u,int v){e[++ed]=edge(v,hed[u]);hed[u]=ed;}
int gfa(int x){return f[x]^x?(f[x]=gfa(f[x])):x;}
void merge(int u,int v){u=gfa(u);v=gfa(v);if(sz[u]>=sz[v]) swap(u,v);f[u]=v;sz[v]+=sz[u];}
void dfs(int u,int fa,int x,int y){
	f[u]=x;s[y].erase(mp(a[u],u));s[x].insert(mp(a[u],u));
	For(i,u) if((v^fa)&&!e[i].vis) dfs(v,u,x,y);
}
int main(){
	//freopen("in","r",stdin);
	scanf("%d%d%d",&n,&m,&Q);ed=1;
	rep(i,1,n) scanf("%d",a+i),f[i]=i,sz[i]=1;
	rep(i,1,m) scanf("%d%d",u+i,v+i);
	rep(i,1,Q) scanf("%d%d",opt+i,id+i);
	rep(i,1,Q) if(opt[i]==2) ban[id[i]]=1;
	rep(i,1,m) if(gfa(u[i])^gfa(v[i])&&!ban[i]) merge(u[i],v[i]),add(u[i],v[i]),add(v[i],u[i]);
	per(i,Q,1) if(opt[i]==2&&(gfa(u[id[i]])^gfa(v[id[i]]))){
		int x=gfa(u[id[i]]),y=gfa(v[id[i]]);
		add(u[id[i]],v[id[i]]),add(v[id[i]],u[id[i]]);
		del[i]=sz[x]<sz[y]?ed:ed-1;
	}
	rep(i,1,n) s[gfa(i)].insert(mp(a[i],i));
	rep(i,1,Q){
		if(opt[i]==1){
			int u=gfa(id[i]),x=s[u].rbegin()->se;
			printf("%d\n",a[x]);a[x]=0;
			s[u].erase(*s[u].rbegin());s[u].insert(mp(0,x));
		}
		else if(del[i]){
			int x=e[del[i]].to;e[del[i]].vis=e[del[i]^1].vis=1;
			dfs(x,0,x,gfa(x));
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define endl '\n'
#define fi first
#define se second
#define pb push_back
#define bit(s, i) (s & (1<<i))

using namespace std;

const int N = 5e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const long long Inf = 0x3f3f3f3f3f3f3f3f;

typedef long long ll;
typedef pair < int, int > ii;

int n, m, q, p[N], siz[N], par[N];

bool ok[N], has[N];

struct query {
	int t;
	int x;
} qry[N];

ii e[N], edge[N], cur;

vector < int > adj[N];

set < ii > st[N];

void init() {
	for(int i=1;i<=n;++i) {
		par[i] = i;
		siz[i] = 1;
	}
}

int get(int x) {
	if(x == par[x]) return x;
	return par[x] = get(par[x]);
}

bool mix(int x, int y) {
	int u = get(x);
	int v = get(y);

	if(u == v) return 0;

	if(siz[u] < siz[v]) {
		par[u] = v;
		siz[v] += siz[u];
		adj[v].pb(u);
		cur = ii(v, u);
	}
	else {
		par[v] = u;
		siz[u] += siz[v];
		adj[u].pb(v);
		cur = ii(u, v);
	}
	return 1;
}

void dfs(int v, vector < int > &res) {
	res.pb(v);
	for(int u : adj[v]) dfs(u, res);
}

int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	// freopen("trash.inp", "r", stdin);
	// freopen("trash.out", "w", stdout);

	cin >> n >> m >> q;
	init();
	for(int i=1;i<=n;++i) cin >> p[i];

	for(int i=1;i<=m;++i) {
		int u, v;
		cin >> u >> v;
		e[i] = ii(u, v);
	}

	for(int i=1;i<=q;++i) {
		cin >> qry[i].t >> qry[i].x;
		if(qry[i].t == 2) ok[qry[i].x] = true;
	}

	for(int i=1;i<=m;++i) if(!ok[i]) mix(e[i].fi, e[i].se);

	for(int i=q;i>=1;--i) if(qry[i].t == 2) {
		int u = e[qry[i].x].fi;
		int v = e[qry[i].x].se;

		if(mix(u, v)) {
			edge[i] = cur;
			has[i] = 1;
		}
	}

	for(int i=1;i<=n;++i) {
		int u = get(i);
		st[u].insert(ii(p[i], i));
	}

	for(int i=1;i<=q;++i) {
		if(qry[i].t == 1)
		{
			int u = get(qry[i].x);
			auto x = *st[u].rbegin();
			cout << p[x.se] << endl;
			st[u].erase(x);
			p[x.se] = 0;
			st[u].insert(ii(p[x.se], x.se));
		} else if (has[i]) {
			int a = edge[i].fi;
			int b = edge[i].se;

			par[b] = b;
			adj[a].pop_back();
			a = get(a);

			vector < int > res;
			dfs(b, res);

			for(int x : res) {
				st[a].erase(ii(p[x], x));
				st[b].insert(ii(p[x], x));
			}
		}
	}
}

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define ll long long
#define sz(x) ((int)(x.size()))
#define M1 1000000007LL
#define M2 998244353LL

typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<ll> vll;
typedef vector<pll> vpl;

#define MAXN 200010
#define MAXM 300010
#define MAXQ 500010
int p[MAXN],ip[MAXN],g[MAXN];
bool del[MAXM],rm[MAXN];
pii edge[MAXM],query[MAXQ],split[MAXM];
set<int> S[MAXN];
vi mergeList[MAXN];

int find(int u) {
	if (g[u] > 0) {
		g[u] = find(g[u]);
		return g[u];
	}
	return u;
}

void buildSet(int u) {
	S[u].insert(p[u]);
	for (int v : mergeList[u]) {
		for (int pv : S[v]) {
			S[u].insert(pv);
		}
	}
}

void merge(int u,int v,int k) {
	u = find(u);
	v = find(v);
	if (u == v) {
		split[k] = pii(0,0);
	}
	else if (g[u] < g[v]) {
		split[k] = pii(u,v);
		buildSet(v);
		mergeList[u].pb(v);
		g[u] += g[v];
		g[v] = u;
	}
	else {
		split[k] = pii(v,u);
		buildSet(u);
		mergeList[v].pb(u);
		g[v] += g[u];
		g[u] = v;
	}
}

void handleQuery(int v) {
	int gv = find(v);
	if (S[gv].empty()) {
		cout << 0 << endl;
	}
	else {
		auto it = S[gv].rbegin();
		int v = ip[*it];
		cout << *it << endl;
		S[gv].erase(*it);
		rm[v] = true;
	}
}

void handleSplit(int k) {
	int u = split[k].first,v = split[k].second;
	if (u == 0) {
		return;
	}
	vi splitList;
	for(int pv : S[v]) {
		splitList.pb(pv);
	}
	for (int pv : splitList) {
		g[ip[pv]] = v;
		if (S[u].count(pv)) {
			S[u].erase(pv);
		}
		if (rm[v]){
			S[v].erase(pv);
		}
	}
	g[v] = -sz(splitList);
}

int main() {
	ios::sync_with_stdio(false);cin.tie(0);

	int n,m,q;
	cin >> n >> m >> q;
	for (int i=1; i<=n; i++) {
		cin >> p[i];
		ip[p[i]] = i;
		rm[i] = false;
		g[i] = -1;
	}

	int u,v;
	for (int i=1; i<=m; i++) {
		cin >> u >> v;
		edge[i] = pii(u,v);
		del[i] = false;
	}

	for (int i=1; i<=q; i++) {
		int qt;
		cin >> qt >> v;
		if (qt == 2) {
			del[v] = true;
		}
		query[i] = pii(qt,v);
	}

	for (int i=1; i<=m; i++) {
		if (del[i]) {
			continue;
		}
		u = edge[i].first,v = edge[i].second;
		merge(u,v,i);
	}

	for (int i=q; i>=1; i--) {
		int qt = query[i].first;
		if (qt == 2) {
			int e = query[i].second;
			u = edge[e].first,v = edge[e].second;
			merge(u,v,e);
		}
	}

	for (int i=1; i<=n; i++) {
		int gr = find(i);
		S[gr].insert(p[i]);
	}

	for (int i=1; i<=q; i++) {
		int qt = query[i].first;
		if (qt == 1) {
			v = query[i].second;
			handleQuery(v);
		}
		else {
			int k = query[i].second;
			handleSplit(k);
		}
	}

	return 0;
}

#include<bits/stdc++.h>
#define mz 1000000007
#define pii pair<int,int>
using namespace std;

int gg[400005][21];

int main()
{
	return 0;
}

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
//#pragma GCC optimize("O3")
//#pragma GCC target("sse4")
//#pragma GCC target("avx2")

#define deb(x) cout << #x << " = " << x << "\n"
#define all(x) (x).begin(), (x).end()
#define len(x) (int) x.size()
#define lsb(x) (x) & -(x)
#define l(x) (x << 1) + 1
#define r(x) (x << 1) + 2
#define v(x) (int)(x - 'a')

#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define lb lower_bound
#define ub upper_bound

using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ld, ld> pld;
typedef pair <ll, ll> pll;

template <class T1, class T2 = less <T1>> using pb_heap = __gnu_pbds::priority_queue <T1, T2, binary_heap_tag>;
template <class T1, class T2 = null_type, class T3 = less <T1>> using pb_map = tree <T1, T2, T3, rb_tree_tag, tree_order_statistics_node_update>;
template <class T1, class T2 = null_type, class T3 = hash <T1>> using pb_umap = gp_hash_table <T1, T2, T3>;
template <class T1, class T2, class T3 = hash <T1>> using umap = unordered_map <T1, T2, T3>;
template <class T> using uset = unordered_set <T>;
template <class T> using vec = vector <T>;

const ll infll = numeric_limits <ll>::max() >> 1;
const int inf = numeric_limits <int>::max() >> 1;
const int N = 5e5 + 1;
int n, m, q, curr;
int arr[N];
int ind[N];

bool vis[N];

pii qry[N];
pii edge[N];

vec <int> roots;

struct Graph {
    int lef[N];
    int rig[N];
    vec <int> adj[N];
} graph;

struct Node {
    int l, r;
    pii mxm;
} node[N << 2];

struct Dsu {
    int par[N];
} dsu;

int root(int u) {
    return dsu.par[u] == u? u: dsu.par[u] = root(dsu.par[u]);
}

void unite(int u, int v) {
    u = root(u);
    v = root(v);
    int p = ++n;
    graph.adj[p].pb(u);
    graph.adj[p].pb(v);
    dsu.par[p] = p;
    dsu.par[u] = p;
    dsu.par[v] = p;
}

void merge(int id, int l, int r) {
    node[id].mxm = max(node[l].mxm, node[r].mxm);
}

void build(int id, int l, int r) {
    node[id].l = l;
    node[id].r = r;
    if(l == r) {
        node[id].mxm.xx = arr[ind[l]];
        node[id].mxm.yy = l;
        return;
    }
    int q = l + r >> 1;
    build(l(id), l, q);
    build(r(id), q + 1, r);
    merge(id, l(id), r(id));
}

void erase(int id, int i) {
    if(node[id].l == node[id].r) {
        node[id].mxm.xx = 0;
        return;
    }
    int q = node[id].l + node[id].r >> 1;
    if(i <= q) {
        erase(l(id), i);
    } else {
        erase(r(id), i);
    }
    merge(id, l(id), r(id));
}

pii query(int id, int l, int r) {
    if(node[id].l == l && node[id].r == r) {
        return node[id].mxm;
    }
    pii res = {0, 0};
    int q = node[id].l + node[id].r >> 1;
    if(l <= q) {
        res = max(res, query(l(id), l, min(q, r)));
    }
    if(r > q) {
        res = max(res, query(r(id), max(q + 1, l), r));
    }
    return res;
}

void dfs(int u) {
    static int t = 0;
    ind[++t] = u;
    graph.lef[u] = t;
    for(int v: graph.adj[u]) {
        dfs(v);
    }
    graph.rig[u] = t;
}

void input() {
    cin >> n >> m >> q;
    for(int i = 1; i <= n; ++i) {
        cin >> arr[i];
    }
    for(int i = 1; i <= m; ++i) {
        int u; cin >> u;
        int v; cin >> v;
        edge[i] = {u, v};
    }
    for(int i = 1; i <= q; ++i) {
        cin >> qry[i].xx;
        cin >> qry[i].yy;
        if(qry[i].xx == 2) {
            vis[qry[i].yy] = 1;
        }
    }
}

void solve() {
    for(int i = 1; i <= n; ++i) {
        dsu.par[i] = i;
    }
    for(int i = 1; i <= m; ++i) {
        if(!vis[i]) {
            int u = edge[i].xx;
            int v = edge[i].yy;
            unite(u, v);
        }
    }
    for(int i = q; i >= 1; --i) {
        if(qry[i].xx == 1) {
            roots.pb(root(qry[i].yy));
        } else {
            int u = edge[qry[i].yy].xx;
            int v = edge[qry[i].yy].yy;
            if(root(u) == root(v)) {
                continue;
            }
            unite(u, v);
        }
    }
    for(int i = 1; i <= n; ++i) {
        if(root(i) == i) {
            dfs(i);
        }
    }
    if(n > 100) {
        cout << "wtf\n";
        return;
    }
    build(0, 1, n);
    reverse(all(roots));
    for(int e: roots) {
        pii p = query(0, graph.lef[e], graph.rig[e]);
        erase(0, p.yy);
        cout << p.xx << "\n";
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    input();
    solve();
}

#include <bits/stdc++.h>
#define lc (id<<1)
#define rc (id<<1|1)
using namespace std;
typedef long long ll;
const int maxn = 5e5+10;
int p[maxn],a[maxn],b[maxn],flag[maxn];
int qur[maxn],id[maxn],f[maxn],tot;
int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt,now;
void add(int u,int v){
    ++cnt,to[cnt] = v,nxt[cnt] = head[u],head[u] = cnt;
    ++cnt,to[cnt] = u,nxt[cnt] = head[v],head[v] = cnt;
}
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}

void unite(int x,int y){
    x = find(x);
    y = find(y);
    if(x==y) return ;
    ++tot;
    add(x,tot),add(y,tot);
    f[tot] = f[x] = f[y] = tot;
}
bool same(int x,int y){
    return find(x)==find(y);
}
int el[maxn],er[maxn],rk[maxn];
void dfs(int u,int pre){
    el[u] = ++now,rk[now] = u;
    for(int i=head[u];i;i=nxt[i]){
        int v = to[i];
        if(v==pre) continue;
        dfs(v,u);
    }
    er[u] = now;
}
int maxs[maxn<<2];
int Max(int i,int j){
    return p[rk[i]]>p[rk[j]]?i:j;
}
void push_up(int id){
    maxs[id] = 0;
    maxs[id] = Max(maxs[id<<1],maxs[id<<1|1]);
}
void build(int id,int l,int r){
    if(l==r){
        maxs[id] = l;
        return ;
    }
    int mid = (l+r)>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    push_up(id);
}

int query(int id,int l,int r,int x,int y){
    if(x<=l&&y>=r) return maxs[id];
    int mid = (l+r)>>1,ans = 0;
    if(x<=mid) ans = Max(ans,query(id<<1,l,mid,x,y));
    if(y>mid) ans = Max(ans,query(id<<1|1,mid+1,r,x,y));
    return ans;
}
void update(int id,int l,int r,int pos,int val){
    if(l==r){
        maxs[id] = val;
        return ;
    }
    int mid = (l+r)>>1;
    if(pos<=mid) update(id<<1,l,mid,pos,val);
    if(pos>mid) update(id<<1|1,mid+1,r,pos,val);
    push_up(id);
}
int main(){
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    tot = n,cnt = 0,now = 0;
    for(int i=1;i<=n+m;i++) f[i] = i;
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    // printf("sss\n");
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a[i],&b[i]);
    }
    for(int i=1;i<=q;i++){
        scanf("%d%d",&qur[i],&id[i]);
        if(qur[i]==2) flag[id[i]] = true;
    }
    for(int i=1;i<=m;i++){
        if(!flag[i]) unite(a[i],b[i]);
    }
    for(int i=q;i>=1;i--){
        if(qur[i]==2){
            int x = id[i];
            if(same(a[x],b[x])) continue;
            unite(a[x],b[x]);
        }
    }
    for(int i=1;i<=tot;i++){
        if(f[i]==i) dfs(i,0);
    }
    build(1,1,now);
    for(int i=1;i<=q;i++){
        if(qur[i]==1){
            int root = find(id[i]);
            int ans = query(1,1,now,el[root],er[root]);
            printf("%d\n", p[rk[ans]]);
            update(1,1,now,ans,0);
        }
        else{
            int root = find(a[id[i]]);
            for(int i=head[root];i;i=nxt[i]){
                int v = to[i];
                f[v] = v;
            }
        }
    }
}

#include <bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = 7e5 + 5;
const int mod = 1e9 + 7;

int n,m,q;
int p[maxn],u[200010],v[200010],vis[300010],fa[maxn],op[500010][2],sz[maxn],boss[500010];
int pos[maxn],dfn[maxn],tot;
struct node {int w,pos;}t[maxn<<2];
vector<int>G[maxn];
int fid(int x){return x==fa[x]?x:fa[x]=fid(fa[x]); }

void dfs(int u) {
	pos[u]=++tot;
	dfn[tot]=u;
	sz[u]=1;
	for(int v:G[u]) dfs(v),sz[u]+=sz[v];
}

void push_up(int rt) {
	if(t[ls].w>t[rs].w) t[rt]=t[ls];
	else t[rt]=t[rs];
}
void build(int rt,int l,int r) {
	t[rt].w=t[rt].pos=0;
	if(l==r) {
		t[rt].w=p[dfn[l]];
		//cout<<l<<','<<t[rt].w<<','<<dfn[l]<<endl;
		t[rt].pos=l;
		return ;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	push_up(rt);
}
void upd(int rt,int l,int r,int z) {
	if(l==r&&r==z) {
		t[rt].w=0;
		return ;
	}
	int mid=l+r>>1;
	if(z<=mid) upd(ls,l,mid,z);
	else upd(rs,mid+1,r,z);
	push_up(rt);
}
node ask(int rt,int l,int r,int ql,int qr)  {//cout<<ql<<','<<qr<<endl;
	if(ql<=l&&r<=qr) return t[rt];
	int mid=l+r>>1;
	node f1,f2;
	f1.w=f2.w=f1.pos=f2.pos=0;
	if(ql<=mid) f1=ask(ls,l,mid,ql,qr);
	if(qr>mid) f2=ask(rs,mid+1,r,ql,qr);
	if(f1.w>f2.w) return f1;
	else return f2;
}
int main() {
    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",&u[i],&v[i]);
    }
    for(int i=1;i<=q;i++) {
    	scanf("%d%d",&op[i][0],&op[i][1]);
    	if(op[i][0]==2) vis[op[i][1]]=1;
    }
    for(int i=1;i<=n+q;i++) fa[i]=i;
    for(int i=1;i<=m;i++) {
    	if(vis[i]) continue;
    	//cout<<i<<endl;
    	int fx=fid(u[i]),fy=fid(v[i]);
    	if(fx!=fy) {
    		n++;
			G[n].pb(fx);
			G[n].pb(fy);
			fa[fx]=n;
			fa[fy]=n;
    	}
    }

    //for(int i=1;i<=n;i++) cout<<fid(i)<<',';cout<<endl;
    for(int i=q;i>=1;i--) {
    	if(op[i][0]==2) {
    		int x=op[i][1];
    		int fx=fid(u[x]),fy=fid(v[x]);
    		if(fx!=fy) {
    			n++;
    			G[n].pb(fx);
    			G[n].pb(fy);
    			fa[fx]=n;
    			fa[fy]=n;
    			//cout<<i<<endl;
    		}

    	} else boss[i]=fid(op[i][1]);
    }
	//for(int i=1;i<=n;i++) cout<<fid(i)<<',';cout<<endl;return 0;
    for(int i=1;i<=n;i++) {
    	if(!dfn[pos[i]]) {
    		//cout<<i<<'_'<<fid(i)<<endl;
    		dfs(fid(i));
    	}
    }    //return 0;
    build(1,1,tot);
/*    cout<<tot<<',';
    for(int i=1;i<=tot;i++) printf("%d ",dfn[i]);
    printf("\n");*/

    for(int i=1;i<=q;i++) {
    	if(op[i][0]==1) {
    		node x=ask(1,1,tot,pos[boss[i]],pos[boss[i]]+sz[boss[i]]-1);
    		//
    		if(x.w>0) upd(1,1,tot,x.pos);
    		printf("%d\n",x.w);
    	}
    }
    return 0;
}

#include<bits/stdc++.h>

using namespace std;
typedef long long int lld;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define trav(a,v) for(auto a:v)
int n,m,q;
int p[4000000];
vector<pair<int,int> >Q,E;
vector<int> tree[4000000];
bool used[4000000];
bool visited[4000000];
class DSU{
  int par[4000000];
  int sz[4000000];
  int Mx[4000000];
public:
  void init(){
    rep(i,0,3*n)par[i]=i,Mx[i]=i,sz[i]=1;
  }
  int root(int node){
    if(par[node]==node)return node;
    par[node]=root(par[node]);
    return par[node];
  }
  int Rep(int node){
    return Mx[root(node)];
  }
  void merge(int a, int b){
    a=root(a);
    b=root(b);
    if(a==b)return;
    if(sz[a]<sz[b])swap(a,b);
    par[b]=a;
    sz[a]+=sz[b];
    Mx[a]=max(Mx[a],Mx[b]);
  }
  bool same(int a, int b){
    a=root(a);
    b=root(b);
    if(a==b)return true;
    return false;
  }
};
DSU D;
int L[4000000];
int R[4000000];
int queries[4000000];
vector<int> ET;
void DFS(int node){
  if(visited[node])return;
  visited[node]=true;
  L[node]=ET.size();
  ET.push_back(node);
  trav(a,tree[node]){
    //cout<<node<<" "<<a<<endl;
    DFS(a);
  }
  R[node]=ET.size()-1;
}
class ST{
  pair<int,int> arr[4000000];
public:
  void build(int a, int b, int node){
    arr[node]={0,node};
    if(a==b)return;
    int mid=(a+b)/2;
    build(a,mid,2*node);
    build(mid+1,b,2*node+1);
  }
  void update(int a, int b, int node, int pos, int val){
    if(pos<a || b<pos)return;
    if(a==b){
      arr[node]={val,pos};
      return;
    }
    int mid=(a+b)/2;
    update(a,mid,2*node,pos,val);
    update(mid+1,b,2*node+1,pos,val);
    arr[node]=max(arr[2*node],arr[2*node+1]);
  }
  pair<int,int> query(int a, int b, int node, int x, int y){
    if(y<a || b<x)return {-1,-1};
    if(x<=a && b<=y)return arr[node];
    int mid=(a+b)/2;
    return max(query(a,mid,2*node,x,y),query(mid+1,b,2*node+1,x,y));
  }
};
ST S;
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin>>n>>m>>q;
  rep(i,0,n)cin>>p[i];
  rep(i,0,m){
    used[i]=false;
    int x,y;
    cin>>x>>y;
    x--;y--;
    E.push_back({x,y});
  }
  rep(i,0,q){
    int type;
    int idx;
    cin>>type>>idx;
    idx--;
    Q.push_back({type,idx});
    if(type==2)used[idx]=true;
  }
  D.init();
  int cnt=n;
  rep(i,0,m){
    if(!used[i]){
      //cout<<i<<endl;
      if(!D.same(E[i].first,E[i].second)){

	tree[cnt].push_back(D.Rep(E[i].first));
	D.merge(cnt,D.Rep(E[i].first));
	tree[cnt].push_back(D.Rep(E[i].second));
	D.merge(cnt,D.Rep(E[i].second));
	cnt++;
      }
    }
  }
  for(int i=q-1;i>-1;i--){
    if(Q[i].first==2){
      if(!D.same(E[Q[i].second].first,E[Q[i].second].second)){
	tree[cnt].push_back(D.Rep(E[Q[i].second].first));
	D.merge(cnt,D.Rep(E[Q[i].second].first));
	tree[cnt].push_back(D.Rep(E[Q[i].second].second));
	D.merge(cnt,D.Rep(E[Q[i].second].second));
	cnt++;
      }
    }else{
      queries[i]=D.Rep(Q[i].second);
    }
  }
  rep(i,0,cnt)visited[i]=false;
  for(int i=cnt-1;i>-1;i--){
    DFS(i);
  }
  //trav(a,ET)cout<<a<<endl;
  //rep(i,0,cnt)cout<<L[i]<<" "<<R[i]<<endl;
  S.build(0,cnt-1,1);
  rep(i,0,n){

    S.update(0,cnt-1,1,L[i],p[i]);
  }
  rep(i,0,q){
    if(Q[i].first==1){
      pair<int,int> in={L[queries[i]],R[queries[i]]};
      pair<int,int> ans=S.query(0,cnt-1,1,in.first,in.second);
      cout<<ans.first<<endl;
      S.update(0,cnt-1,1,ans.second,0);
    }
  }
  return 0;
}

#pragma region Macros
#pragma GCC optimize("O3")
#pragma GCC target("avx2,avx")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define rep2(i, a, b) for(ll i = a; i <= b; ++i)
#define rep(i, n) for(ll i = 0; i < n; ++i)
#define rep3(i, a, b) for(ll i = a; i >= b; --i)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define vll vector<ll>
#define vpi vector<pii>
#define vpll vector<pll>
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size)                                                                                \
    vector<type> name(size);                                                                                \
    IN(name)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w)                                                                                \
    vector<vector<type>> name(h, vector<type>(w));                                                                                \
    IN(name)
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define fi first
#define se second
#define all(c) begin(c), end(c)
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
using namespace std;
string YES[2] = {"NO", "YES"};
string Yes[2] = {"No", "Yes"};
string yes[2] = {"no", "yes"};
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
#define si(c) (int)(c).size()
#define INT(...)                                                                                \
    int __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define LL(...)                                                                                \
    ll __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define STR(...)                                                                                \
    string __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                \
    char __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                \
    double __VA_ARGS__;                                                                                \
    IN(__VA_ARGS__)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &... tail) {
    scan(head);
    IN(tail...);
}
template <class T, class S> inline bool chmax(T &a, S b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T, class S> inline bool chmin(T &a, S b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
vi iota(int n) {
    vi a(n);
    iota(all(a), 0);
    return a;
}
template <typename T> vi iota(vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(all(res), 0);
    sort(all(res), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    sort(all(y));
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
int popcount(ll x) { return __builtin_popcountll(x); }
struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(15);
    }
} setup_io;
int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return move(res);
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        cin >> a >> b >> c;
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return move(res);
}

#define i128 __int128_t
#define ull unsigned long long int
#define TEST                                                                                \
    INT(testcases);                                                                                \
    while(testcases--)
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    for(auto &e : v) cout << e << " ";
    cout << endl;
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    cout << "(" << p.fi << ", " << p.se << ")";
    return os;
}
template <class S, class T> string to_string(pair<S, T> p) { return "(" + to_string(p.first) + "," + to_string(p.second) + ")"; }
template <class A> string to_string(A v) {
    if(v.empty()) return "{}";
    string ret = "{";
    for(auto &x : v) ret += to_string(x) + ",";
    ret.back() = '}';
    return ret;
}

void dump() { cerr << endl; }
template <class Head, class... Tail> void dump(Head head, Tail... tail) {
    cerr << to_string(head) << " ";
    dump(tail...);
}
#define endl '\n'
#ifdef _LOCAL
#undef endl
#define debug(x)                                                                                \
    cout << #x << ": ";                                                                                \
    dump(x)
#else
#define debug(x)
#endif
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

// int rnd(int n) { return uniform_int_distribution<int>(0, n - 1)(rng); }
// ll rndll(ll n) { return uniform_int_distribution<ll>(0, n - 1)(rng); }

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
#pragma endregion

vector<int> a;
template <typename T = int> struct UnionFind {
    vector<int> data;
    vector<set<int>> s;
    struct A {
        int y, d;
        A() = default;
    };
    vector<A> hist;
    int num;

    UnionFind(int n) : num(n) {
        data.assign(n, -1);
        s.resize(n);
        rep(i, n) s[i].emplace(a[i]);
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if(x == y) {
            A a;
            a.y = -1;
            hist.eb(a);
            return false;
        }
        num--;
        if(data[x] > data[y]) swap(x, y);
        data[x] += data[y];
        A a;
        a.y = y, a.d = data[y];
        for(auto &e : s[y]) s[x].emplace(e);
        hist.eb(a);
        data[y] = x;
        return true;
    }

    int find(int x) {
        if(data[x] < 0) return x;
        return (data[x] = find(data[x]));
    }

    void undo() {
        auto &a = hist.back();
        hist.pop_back();
        if(a.y == -1) { return; }
        int y = a.y;
        int x = data[y];
        data[x] -= a.d;
        data[y] = a.d;
        for(auto it = s[y].begin(); it != s[y].end();) {
            auto it2 = s[x].find(*it);
            if(it2 != s[x].end())
                s[x].erase(it2), it++;
            else
                it = s[y].erase(it);
        }
    }
    int get(int x) {
        x = find(x);
        if(s[x].empty())
            return 0;
        else {
            int res = *s[x].rbegin();
            s[x].erase(--s[x].end());
            return res;
        }
    }
};

int main() {
    INT(n, m, q);
    a.resize(n);
    rep(i, n) cin >> a[i];
    vector<pii> E;
    rep(i, m) {
        INT(x, y);
        x--, y--;
        E.eb(x, y);
    }
    vi used(m);
    vi edges;
    vector<pii> query;
    rep(i, q) {
        INT(t, s);
        query.eb(t, --s);
        if(t == 2) {
            edges.eb(s);
            used[s] = true;
        }
    }
    rep(i, m) if(!used[i]) edges.eb(i);
    UnionFind uf(n);
    reverse(all(edges));
    for(auto i : edges) uf.unite(E[i].fi, E[i].se);
    for(auto [t, s] : query) {
        if(t == 1) {
            cout << uf.get(s) << endl;
        } else
            uf.undo();
    }
}

#include <bits/stdc++.h>
using namespace std;

int c[200005];
int indx[200005];

int a[300005];
int b[300005];

int op[500005];
int x[500005];

vector<int> AdjList[400005];

bool picked[300005];
int order[300005];

int p2[400005];

int n, m, q;
void init1(){
    for(int i = 1; i <= 2*n; i ++){
        p2[i] = i;
    }
}

int findSet(int i){
    return (p2[i] == i) ? i : (p2[i] = findSet(p2[i]));
}

bool isSameSet[300005];

// merge with new node of higher index than any of previous nodes
void unionSet(int u, int v){
    int x = findSet(u);
    int y = findSet(v);

    if(x == y){return;}
    if(x > y){swap(x, y);}
    p2[x] = y;
}

int p[400005][20];

int l[400005];
int r[400005];

int cnt = 0;
void dfs(int u){
    l[u] = cnt ++;
    for(int v: AdjList[u]){
        dfs(v);
    }
    r[u] = cnt;
}

int val[(1<<20)+5];
int f[400005];

void init(int i = 1, int s = 0, int e = 2*n){
    if(s == e){
        val[i] = f[s];
        return;
    }else{
        int l = (i<<1);
        int r = (i<<1)|1;
        int m = (s+e)>>1;
        init(l, s, m);
        init(r, m+1, e);
        val[i] = max(val[l], val[r]);
    }
}

int rmq(int x, int y, int i = 1, int s = 0, int e = 2*n){
    if(x <= s && e <= y){
        return val[i];
    }else{
        int l = (i<<1);
        int r = (i<<1)|1;
        int m = (s+e)>>1;

        if(x > m){
            return rmq(x, y, r, m+1, e);
        }else if(y <= m){
            return rmq(x, y, l, s, m);
        }else{
            return max(rmq(x, y, r, m+1, e), rmq(x, y, l, s, m));
        }
    }
}

void update(int p, int v, int i = 1, int s = 0, int e = 2*n){
    if(s == e){
        val[i] = v;
        return;
    }else{
        int l = (i<<1);
        int r = (i<<1)|1;
        int m = (s+e)>>1;

        if(p > m){
            update(p, v, r, m+1, e);
        }else if(p <= m){
            update(p, v, l, s, m);
        }
        val[i] = max(val[l], val[r]);
    }
}

int main(){
    scanf("%d%d%d", &n, &m, &q);

    for(int i = 1; i <= n; i ++){
        scanf("%d", &c[i]);
        indx[c[i]] = i;
    }

    memset(picked, false, sizeof(picked));
    for(int i = 1; i <= m; i ++){
        scanf("%d%d", &a[i], &b[i]);
    }

    int cnt = 0;
    for(int i = 1; i <= q; i ++){
        scanf("%d%d", &op[i], &x[i]);
        if(op[i] == 2){
            picked[x[i]] = true;
            order[cnt ++] = x[i];
        }
    }

    for(int i = 1; i <= m; i ++){
        if(!picked[i]){
            order[cnt ++] = i;
        }
    }

    assert(cnt == m);
    reverse(order, order+m);
    memset(p, -1, sizeof(p));
    int newNode = n+1;
    init1();
    for(int i = 0; i < m; i ++){
        int x = a[order[i]];
        int y = b[order[i]];
        //printf("merge %d and %d\n", x, y);

        int u = findSet(x);
        int v = findSet(y);

        isSameSet[i] = (u == v);
        if(u == v){continue;}

        unionSet(newNode, u);
        unionSet(newNode, v);

        p[u][0] = newNode;
        p[v][0] = newNode;

        //printf("edge: %d %d\n", newNode, u);
        //printf("edge: %d %d\n", newNode, v);
        AdjList[newNode].push_back(u);
        AdjList[newNode].push_back(v);

        newNode ++;
    }

    for(int k = 1; k <= 19; k ++){
        for(int i = 1; i <= 2*n; i ++){
            if(p[i][k-1] == -1){
                p[i][k] = -1;
            }else{
                p[i][k] = p[p[i][k-1]][k-1];
            }
        }
    }

    for(int i = 2*n; i >= 1; i --){
        if(p[i][0] == -1){
            //printf("source=%d\n", i);
            dfs(i);
        }
    }

    memset(f, 0, sizeof(f));
    for(int i = 1; i <= n; i ++){
        f[l[i]] = c[i];
        //printf("l[%d] = %d\n", i, l[i]);
        //printf("f[%d]=%d\n", l[i], c[i]);
    }
    init();

    int curNode = newNode;
    //printf("newNode: %d\n", newNode);

    int curIndx = m-1;
    for(int i = 1; i <= q; i ++){
        if(op[i] == 1){
            int y = x[i];
            for(int k = 19; k >= 0; k --){
                if(p[y][k] == -1){continue;}
                if(p[y][k] < curNode){
                    y = p[y][k];
                }
            }
            /*printf("debug: %d %d %d\n", l[y], r[y], 22323123);
            for(int i = 0; i < 2*n; i ++){
                printf("%d ", rmq(i, i));
            }
            printf("\n");*/
            int ans = rmq(l[y], r[y]);
            if(ans != 0){
                update(l[indx[ans]], 0);
            }
            printf("%d\n", ans);
        }else{
            if(!isSameSet[curIndx]){
                curNode --;
            }
            //printf("curNode=%d\n", curNode);
            curIndx --;
        }
    }

    return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(auto i = (a); i < (b); i++)
#define pb push_back
#define fs first
#define sc second
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ii> vii;
typedef vector<vii> vvii;

const double EPS = 1e-9;

typedef pair<int,ii> T;

set<ii> BST[200'050];
struct union_find {
	vi p;
    vi sz;
    vi A;

    vector<set<int>> BACK;

	union_find(int n, vi &b) : A(b), p(n), sz(n,1), BACK(n,set<int>()) {
        rep(i,0,n) p[i] = i;
        rep(i,0,n) BST[i].insert(ii(A[i],i));
    }

    stack<T> q;
    int cur = 0;

	int find(int a) {
        if(a == p[a]) return a;
        return find(p[a]);
    }

    int best(int a) {
        a = find(a);
        if(BST[a].size() == 0) return 0;
        ii val = *(--BST[a].end());
        BST[a].erase(val);
        A[val.sc] = 0;
        return val.fs;
    }

	bool joined(int a, int b) {
        return find(a) == find(b);
    }

    void change(int at, int from, int to) {
        BST[from].erase(ii(A[at],at));
        BST[to].insert(ii(A[at],at));
        for(auto a : BACK[at]) {
            change(a, from, to);
        }
    }

	void unite(int a, int b) {

        a = find(a);
        b = find(b);
        if(a == b) {
            q.push(T(-1,ii(0,0)));
            return;

        }

        if(sz[find(a)] < sz[find(b)]) {
            // go through smaller size remove and add to other
            change(a, a, b);

            sz[find(b)] += sz[find(a)];

            q.push( T(cur, ii(a, p[a])) );
            BACK[b].insert(find(a));

            p[find(a)] = find(b);

        } else {
            change(b, b, a);

            sz[find(a)] += sz[find(b)];
            q.push( T(cur, ii(b, p[b])) );

            BACK[a].insert(find(b));

            p[find(b)] = find(a);

        }
    }

    void pop() {
        T a = q.top();
        q.pop();
        if(a.fs == -1) return;
        change(a.sc.fs, find(a.sc.fs), a.sc.fs);
        BACK[find(a.sc.fs)].erase(a.sc.fs);
        sz[find(a.sc.fs)] -= sz[a.sc.fs];
        p[a.sc.fs] = a.sc.sc;
    }
};

int main() {
    cin.sync_with_stdio(false);
    int n,m,q;
    cin >> n >> m >> q;

    vi A(n);
    rep(i,0,n) cin >> A[i];
    vii E;
    rep(i,0,m) {
        int u,v;
        cin >> u >> v;
        u--;v--;
        E.pb(ii(u,v));
    }
    union_find un(n, A);

    vii OP(q);
    rep(i,0,q) cin >> OP[i].fs >> OP[i].sc;
    for(int i = q-1; i >= 0; i--) {
        if(OP[i].fs == 2) {
            un.unite(E[OP[i].sc-1].sc, E[OP[i].sc-1].fs);
        }
    }
    for(int i = 0; i < q; i++) {
        if(OP[i].fs == 1) {
            int val = un.best(OP[i].sc-1);
            cout << val << endl;
        } else {
            un.pop();
        }
    }
}

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
#define rl register long long
#define N 300010
ll pi[N],cnt,fa[N],n,m,q,hd[N],t[N<<1],nxt[N<<1],lnm[N<<1],rnm[N<<1],dcnt,adfn[N];
inline void add_edge(rl u,rl v){nxt[++cnt]=hd[u],t[cnt]=v,hd[u]=cnt;}
inline ll ffa(rl x){return fa[x]==x?x:fa[x]=ffa(fa[x]);}
struct qry{
	ll tp,v,prt;
}qrys[N<<2];
struct edge{ll u,v;bool dll;}es[N<<1];
inline ll mmin(rl a,rl b){return a<b?a:b;}
inline ll mmax(rl a,rl b){return a>b?a:b;}
struct ST{
	ll mxi[N<<2];
	inline void pushup(rl u){mxi[u]=mmax(mxi[u<<1],mxi[u<<1|1]);}
	void build(rl cl,rl cr,rl u){if(cl==cr){mxi[u]=pi[adfn[cl]];return;}rl mid=(cl+cr)>>1;build(cl,mid,u<<1),build(mid+1,cr,u<<1|1);pushup(u);}
	ll query(rl ql,rl qr,rl cl,rl cr,rl u){
		if(cl>qr || cr<ql) return 0LL;
		if(ql<=cl && qr>=cr) return mxi[u];
		rl mid=(cl+cr)>>1;return mmax(query(ql,qr,cl,mid,u<<1),query(ql,qr,mid+1,cr,u<<1|1));
	}
	void del(rl ql,rl qr,rl cl,rl cr,rl u,rl p){
		// printf("del: %lld %lld %lld\n", cl,cr,u);
		if(cl>qr || cr<ql) return;
		if(ql<=cl && qr>=cr){if(mxi[u]==p) del2(u,p,cl,cr);return;}
		rl mid=(cl+cr)>>1;del(ql,qr,cl,mid,u<<1,p),del(ql,qr,mid+1,cr,u<<1|1,p);
		pushup(u);
	}
	void del2(rl u,rl p,rl cl,rl cr){
		// printf("%lld %lld\n",cl,u );
		rl mid=(cl+cr)>>1;if(cl==cr){mxi[u]=0;return;}
		mxi[u<<1]==p?del2(u<<1,p,cl,mid):del2(u<<1|1,p,mid+1,cr);
		pushup(u);
	}
}T;
void dfs(rl u){
	if(!hd[u]){adfn[++dcnt]=u;lnm[u]=rnm[u]=dcnt;return;}
	lnm[u]=2e17;
	for(rl p=hd[u];p;p=nxt[p])
		dfs(t[p]),lnm[u]=mmin(lnm[u],lnm[t[p]]),rnm[u]=mmax(rnm[u],rnm[t[p]]);
}
int main(){
	scanf("%lld %lld %lld",&n,&m,&q);
	for(rl i=1;i<=n;++i)
		scanf("%lld",&pi[i]);
	for(rl i=1;i<=m;++i)
		scanf("%lld %lld",&es[i].u,&es[i].v),es[i].dll=false;
	for(rl i=0;i<q;++i)
		scanf("%lld %lld",&qrys[i].tp,&qrys[i].v),qrys[i].tp==2?es[qrys[i].v].dll=true:0LL;
	for(rl i=1;i<=m;++i) if(!es[i].dll)
		qrys[q++]=(qry){2LL,i,0LL};
	for(rl i=1;i<=n;++i)
		fa[i]=i;
	for(rl i=q-1;i>=0;--i){
		if(qrys[i].tp==2){
			if(ffa(es[qrys[i].v].u)==ffa(es[qrys[i].v].v)) continue;
			++n;
			add_edge(n,ffa(es[qrys[i].v].u)),add_edge(n,ffa(es[qrys[i].v].v));
			fa[ffa(es[qrys[i].v].u)]=fa[ffa(es[qrys[i].v].v)]=fa[n]=n;
		}else qrys[i].prt=ffa(qrys[i].v);
	}
	for(rl i=1;i<=n;++i) if(ffa(i)!=ffa(1)){
		++n;
		add_edge(n,ffa(i)),add_edge(n,ffa(1));
		fa[ffa(i)]=fa[ffa(1)]=fa[n]=n;
	}
	dfs(n);
	T.build(1,n,1);
	// for(rl i=1;i<=dcnt;++i)
		// printf("%lld\n", adfn[i]);
	for(rl i=0,j;i<q;++i) if(qrys[i].tp==1){
		// printf("%lld %lld\n", lnm[qrys[i].prt],rnm[qrys[i].prt]);
		j=T.query(lnm[qrys[i].prt],rnm[qrys[i].prt],1,n,1);
		printf("%lld\n", j);T.del(lnm[qrys[i].prt],rnm[qrys[i].prt],1,n,1,j);
	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM], qs[MAXQ+MAXM];
bool del[MAXN], used[MAXM];

int find_set(int v){
    for (; v != p[v]; v = p[v], amt++);
    return v;
}
int f_find_set(int v){ return v==p[v]?v:p[v]=find_set(p[v]); }
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; sz[b]=0;
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}

void fsc(int &x){
    register int c;
    x = 0; c=getchar();
    for(;(c>47 && c<58);c=getchar())
        x = (x<<1) + (x<<3) +c -48;
}
void solve(){
    fsc(n), fsc(m), fsc(q);
    for (int i = 0; i < n; i++) fsc(a[i]);
    for (int i = 0; i < m; i++) fsc(ed[i][0]), fsc(ed[i][1]), ed[i][0]--, ed[i][1]--;
    memset(used, 0, sizeof(used));
    for (int i = 0; i < q; i++){
        ar<int, 2> c; fsc(c[0]), fsc(c[1]), --c[1];
        qs[i]=c; if (c[0] == 2) used[c[1]]=1;
    }
    for (int i = 0; i < m; i++) if (!used[i]) qs[q] = ar<int, 2>{2, i}, q++;
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    iota(p, p+n, 0); fill(sz, sz+n, 1); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        if (p[i] != i) ch[p[i]].push_back(i);
    }
    for (int i = 0; i < n; i++){
        loc[i] = f_find_set(i); ans[loc[i]].insert({a[i], i});
    }
    for (int i = 0; i < q; i++){
        auto c = qs[i];
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << 0 <<  '\n'; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            printf("%d\n", cans[0]); er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1) continue;
            dfs(v, loc[v], v);

        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
using namespace std;
const int maxn = 2e5+10;
const int maxm = 3e5+10;
const int maxq = 5e5+10;

int read(){
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<3)+(x<<1)+c-48;c=getchar();}
	return x*f;
}

int k,m,n,q;
int T[maxn<<1],p[maxn<<1],fa[maxn<<1],ch[maxn<<1][2],tot=0;
int L[maxn<<1],R[maxn<<1],a[maxn],tim=0,Fa[maxn<<1][18];
struct node{
	int x,y;
}E[maxm];
int vis[maxm];
pair<int,int> P[maxq];
int find(int x){if(x==fa[x])return x;return fa[x]=find(fa[x]);}
void dfs(int x){
	L[x]=tim+1;
	for(int i=1;i<=17;i++)Fa[x][i]=Fa[Fa[x][i-1]][i-1];
	if(x<=n)a[++tim]=p[x];
	if(ch[x][0])dfs(ch[x][0]);
	if(ch[x][1])dfs(ch[x][1]);
	R[x]=tim;
}
int max_[maxn<<2];
void build(int k,int l,int r){
	if(l==r){max_[k]=a[l];return;}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	max_[k]=max(max_[k<<1],max_[k<<1|1]);
}
int query(int k,int l,int r,int ls,int rs){
	if(ls<=l && r<=rs)return max_[k];
	int mid=(l+r)>>1,ans=0;
	if(mid>=ls)ans=query(k<<1,l,mid,ls,rs);
	if(mid+1<=rs)ans=max(query(k<<1|1,mid+1,r,ls,rs),ans);
	return ans;
}

void modify(int k,int l,int r,int v){
	if(l==r){max_[k]=0;return;}
	int mid=(l+r)>>1;
	if(max_[k<<1]==v)modify(k<<1,l,mid,v);
	else modify(k<<1|1,mid+1,r,v);
	max_[k]=max(max_[k<<1],max_[k<<1|1]);
}

int main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)p[i]=read();
	for(int i=1;i<=m;i++){
		E[i].x=read();E[i].y=read();
	}
	for(int i=1;i<=q;i++){
		P[i].first=read();P[i].second=read();
		if(P[i].first==2)vis[P[i].second]=1;
	}
	for(int i=1;i<=n;i++){fa[i]=i;T[i]=q+1;}tot=n;
	for(int i=1;i<=m;i++){
		if(vis[i])continue;
		int X=find(E[i].x),Y=find(E[i].y);
		if(X!=Y){
			tot++;
			T[tot]=q+1;
			Fa[X][0]=Fa[Y][0]=fa[X]=fa[Y]=fa[tot]=tot;
			ch[tot][0]=X;ch[tot][1]=Y;
		}
	}
	for(int i=q;i>=1;i--){
		if(P[i].first==2){
			int X=find(E[P[i].second].x),Y=find(E[P[i].second].y);
			if(X!=Y){
				tot++;
				T[tot]=i;
				Fa[X][0]=Fa[Y][0]=fa[X]=fa[Y]=fa[tot]=tot;
				ch[tot][0]=X;ch[tot][1]=Y;
			}
		}
	}
	for(int i=1;i<=tot;i++)if(fa[i]==i)dfs(i);
	build(1,1,n);
	for(int i=1;i<=q;i++){
		if(P[i].first==1){
			int x=P[i].second;
			for(int j=17;j>=0;j--)if(T[Fa[x][j]]>i)x=Fa[x][j];
			int ans=query(1,1,n,L[x],R[x]);
			printf("%d\n",ans);
			modify(1,1,n,ans);
		}
	}
	return 0;
}

#include <bits/stdc++.h>
#define DEBUG if(0)
#define lli long long int
#define ldouble long double
using namespace std;

const int maxN = 2e5, maxNE = 5e5, maxE = 3e5, maxQ = 5e5; int n, m, q;
const int inf = maxNE + 1;

int p[maxN];
struct Edge
{
  int u, v, done;
  void read() { scanf("%d %d", &u, &v), done = false; u--, v--; }
};
Edge edges[maxE];

struct Query
{
  int type, value, artificial, queryRoot;
  void read() { scanf("%d %d", &type, &value); value--; }
};
Query queries[maxQ];

int parent[maxNE];
int root(int u)
{
  return parent[u] < 0 ? u : parent[u] = root(parent[u]);
}
vector<int> tree[maxNE];
void merge(int u, int v)
{
  if ((u = root(u)) == (v = root(v))) return;
  // if (parent[u] > parent[v]) swap(u, v);
  parent[u] += parent[v];
  parent[v] = u;
  tree[u].push_back(v), tree[v].push_back(u);
}

void printNode(int u)
{
  printf("%c%d", u < n ? 'v' : 'q', u);
  if (u < n) printf("-%d", p[u]);
}
void printTree(int u = 0, int prv = -1, int depth = 0)
{
  for (int i = 0; i < depth; i++) printf("   ");
  printNode(u); printf("\n");
  for (int v: tree[u])
    if (v != prv)
      printTree(v, u, depth + 1);
}

bool visited[maxNE];
vector<int> roots;
void visit(int u)
{
  if (visited[u]) return;
  visited[u] = true;
  for (int v: tree[u]) visit(v);
}

vector<vector<int>> eulerTours;
int myEulerTour[maxNE], in[maxNE], out[maxNE];
void buildEulerTour(int u, int prv = -1)
{
  myEulerTour[u] = eulerTours.size() - 1;
  in[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
  for (int v: tree[u])
    if (v != prv)
      buildEulerTour(v, u);
  out[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
}

struct MaxData
{
  int value, vertex;
  MaxData operator+(const MaxData &other)
  {
    if (value > other.value)
      return *this;
    return other;
  }
};
const MaxData maxNil = MaxData{-1, -1};

template<class T>
struct Segtree
{
  int size;
  T nil;
  vector<T> data;
  vector<T> st;
  Segtree() { }
  Segtree(int size, T nil) : size(size), nil(nil)
  {
    data.resize(size);
    st.resize(4*size);
  }
  Segtree(vector<T> &data, T nil) : size(data.size()), data(data), nil(nil)
  {
    st.resize(4*size);
    build();
  }
  void build() { build(1, 0, size - 1); }
  T query(int qlo, int qhi) { return query(qlo, qhi, 1, 0, size - 1); }
  void update(int pos, T value) { update(pos, value, 1, 0, size - 1); }
  void build(int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo];
      return;
    }
    int mid = (lo + hi) >> 1;
    build(2*i, lo, mid), build(2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
  T query(int qlo, int qhi, int i, int lo, int hi)
  {
    if (hi < qlo || lo > qhi) return nil;
    if (lo >= qlo && hi <= qhi) return st[i];
    int mid = (lo + hi) >> 1;
    return query(qlo, qhi, 2*i, lo, mid) + query(qlo, qhi, 2*i + 1, mid + 1, hi);
  }
  void update(int pos, T &value, int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo] = value;
      return;
    }
    int mid = (lo + hi) >> 1;
    if (pos <= mid) update(pos, value, 2*i, lo, mid);
    else update(pos, value, 2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
};
vector<Segtree<MaxData>> psegs;

int main()
{
  while (scanf("%d %d %d", &n, &m, &q) != EOF)
  {
    memset(parent, -1, sizeof(parent));
    for (int i = 0; i < maxNE; i++) tree[i].clear();

    for (int i = 0; i < n; i++)
      scanf("%d", &p[i]);
    for (int i = 0; i < m; i++)
      edges[i].read();

    for (int i = 0; i < q; i++)
    {
      queries[i].read();
      if (queries[i].type == 2)
        edges[queries[i].value].done = true;
    }

    int artificials = n;
    for (int i = 0; i < m; i++)
      if (!edges[i].done)
      {
        Edge &e = edges[i];
        if (root(e.u) == root(e.v)) continue;
        merge(artificials, e.u), merge(artificials, e.v);
        artificials++;
      }

    for (int i = q - 1; i >= 0; i--)
      if (queries[i].type == 2)
      {
        Edge &e = edges[queries[i].value];
        if (root(e.u) == root(e.v)) continue;
        merge(artificials, e.u), merge(artificials, e.v);
        artificials++;
      }
      else
        queries[i].queryRoot = root(queries[i].value);

    memset(visited, false, sizeof(visited));
    roots.clear();
    for (int i = artificials - 1; i >= 0; i--)
      if (!visited[i])
      {
        visit(i);
        roots.push_back(i);
      }

    eulerTours.clear(), psegs.clear();
    for (int i = 0; i < roots.size(); i++)
    {
      eulerTours.push_back(vector<int>());
      buildEulerTour(roots[i]);
      psegs.push_back(Segtree<MaxData>(eulerTours.back().size(), maxNil));
      for (int j = 0; j < eulerTours.back().size(); j++)
      {
        int u = eulerTours.back()[j];
        psegs.back().data[j].value = u < n ? p[u] : -1;
        psegs.back().data[j].vertex = u < n ? u : -1;
      }
      psegs.back().build();
    }

    DEBUG
    {
      for (int i = 0; i < roots.size(); i++)
      {
        printTree(roots[i]);
        printf("--------\n");
      }
      for (int i = 0; i < eulerTours.size(); i++)
      {
        for (int u: eulerTours[i])
        {
          printNode(u);
          printf(" ");
        }
        printf("\n-----\n");
      }
    }

    for (int i = 0; i < q; i++)
      if (queries[i].type == 1)
      {
        int u = queries[i].value, met = myEulerTour[u];
        DEBUG printf("\tquery %d %d >= %d\n", u + 1, met, i + 1);

        int highestQuery = queries[i].queryRoot;
        int lo = in[highestQuery], hi = out[highestQuery];
        DEBUG printf("\t\thighestQuery: %d\n", highestQuery);

        MaxData ans = psegs[met].query(lo, hi);
        printf("%d\n", ans.value);

        psegs[met].update(in[ans.vertex], maxNil);
        psegs[met].update(out[ans.vertex], maxNil);
      }
  }
  return 0;
}

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 5e5+5;

int A[N];
int del_edges[N];
pair<int,int> E[N];
vector<pair<int,int>> queries;

vector<int> fu_set[N];
set<pair<int, int>> R_set[N];
vector<pair<pair<int, int>, int>> mem_op;
int oj[N];

void un(int a, int b, bool mem, int num)
{
	if(oj[a] != oj[b])
	{
		int x = oj[a];
		int y = oj[b];
		if(fu_set[x].size() < fu_set[y].size()) swap(x, y);
		while(!fu_set[y].empty())
		{
			oj[fu_set[y].back()] = x;
			fu_set[x].push_back(fu_set[y].back());
		       	fu_set[y].pop_back();

			if(mem) mem_op.push_back({{x, y}, num});
		}
	}
}

int main()
{
	int n, m, q;
	scanf("%d%d%d",&n,&m,&q);

	for(int i=1;i<=n;i++)
	{
		scanf("%d",&A[i]);
	}

	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		E[i] = make_pair(a,b);
		del_edges[i] = false;
	}

	for(int i=1;i<=q;i++)
	{
		int r, x;
		scanf("%d%d",&r,&x);
		queries.emplace_back(r,x);
		if(r==2) del_edges[x] = true;
	}

	for(int i=1;i<=n;i++)
	{
		oj[i] = i;
		fu_set[i].push_back(i);
	}

	for(int i=1;i<=m;i++)
	{
		if(!del_edges[i]) un(E[i].first, E[i].second, false, i);
	}

	for(int i=int(queries.size())-1;i>=0;i--)
	{
		if(queries[i].first==2) un(E[i].first, E[i].second, true, i);
	}

	for(int i=1;i<=n;i++)
	{
		for(auto z : fu_set[i])
		{
			R_set[i].insert(make_pair(A[z], z));
		}
	}

	for(int i=0;i<int(queries.size());i++)
	{
		if(queries[i].first == 1)
		{
			int x = oj[queries[i].second];
			auto it = R_set[x].end();
			it--;
			int id = it->second;
			R_set[x].erase(it);
			printf("%d\n", A[id]);
			A[id] = 0;
			R_set[x].insert(make_pair(0, id));
		}

		else
		{
			while(!mem_op.empty() && mem_op.back().second == i)
			{
				int y = mem_op.back().first.first;
				int x = mem_op.back().first.second;

				int id = fu_set[y].back();
				R_set[y].erase(R_set[y].find(make_pair(A[id], id)));
				R_set[x].insert(make_pair(A[id], id));

				oj[fu_set[y].back()] = x;
				fu_set[x].push_back(fu_set[y].back());
		       		fu_set[y].pop_back();
				mem_op.pop_back();
			}
		}
	}
}

#include <bits/stdc++.h>
#define DIM 800010
using namespace std;

vector <int> L[DIM],w[DIM];
pair <int,int> poz[DIM],mch[DIM];
int aint[DIM*4],sol[DIM],v[DIM],E[DIM],t[DIM],g[DIM],f[DIM];
struct query{
    int tip,val;
} qry[DIM];

int n,m,q,i,j,x,y,k,el;

int get_rad (int x){
    int nr = x;
    while (t[x] > 0)
        x = t[x];

    while (t[nr] > 0){
        int aux = t[nr];
        t[nr] = x;
        nr = aux;
    }

    return x;
}

void uneste (int x, int y){
    int radx = get_rad (x), rady = get_rad (y);
    if (radx != rady){
        n++;
        L[n].push_back(radx);
        L[n].push_back(rady);

        t[n] += t[radx] + t[rady];
        t[radx] = n, t[rady] = n;
    }
}

void update (int nod, int st, int dr, int poz, int val){
    if (st == dr){
        aint[nod] = val;
        return;
    }
    int mid = (st+dr)>>1;
    if (poz <= mid)
        update (nod<<1,st,mid,poz,val);
    else update ((nod<<1)|1,mid+1,dr,poz,val);

    if (v[aint[nod<<1]] > v[aint[(nod<<1)|1]])
        aint[nod] = aint[nod<<1];
    else aint[nod] = aint[(nod<<1)|1];
}

int query (int nod, int st, int dr, int x, int y){
    int soll = n+1;
    if (x <= st && dr <= y)
        return aint[nod];

    int mid = (st+dr)>>1;
    if (x <= mid){
        int val = query (nod<<1,st,mid,x,y);
        if (v[val] > v[soll])
            soll = val;
    }
    if (y > mid){
        int val = query ((nod<<1)|1,mid+1,dr,x,y);
        if (v[val] > v[soll])
            soll = val;
    }
    return soll;
}
void dfs (int nod, int tata){
    E[++k] = nod;
    poz[nod].first = k;

    update (1,1,n,poz[nod].first,nod);

    for (auto vecin : L[nod])
        if (vecin != tata)
            dfs (vecin,nod);
    poz[nod].second = k;
}
void dfs2 (int nod, int tata){

    for (int i=w[nod].size()-1;i>=0;i--){
        int pos = query (1,1,n,poz[nod].first,poz[nod].second);
        sol[el - w[nod][i] + 1] = v[pos];
        v[pos] = 0;
        update (1,1,n,poz[nod].first,pos);
    }

    for (auto vecin : L[nod])
        if (vecin != tata)
            dfs2 (vecin,nod);

}

int main (){

    //FILE *fin = fopen ("date.in","r");
    //FILE *fout = fopen ("date.out","w");

    FILE *fin = stdin;
    FILE *fout = stdout;

    fscanf (fin,"%d%d%d",&n,&m,&q);

    for (i=1;i<=n;i++)
        fscanf (fin,"%d",&v[i]);

    for (i=1;i<=m;i++)
        fscanf (fin,"%d%d",&mch[i].first,&mch[i].second);

    for (i=1;i<=q;i++){
        fscanf (fin,"%d%d",&qry[i].tip,&qry[i].val);
        if (qry[i].tip == 2)
            f[qry[i].val] = 1;
    }

    memset (t,-1,sizeof t);

    /// mai adaug eu query uri pana am toate muchiile sterse
    for (i=1;i<=m;i++)
        if (!f[i]){
            int radx = get_rad (mch[i].first), rady = get_rad (mch[i].second);
            if (radx != rady){
                if (t[radx] > t[rady])
                    swap (radx,rady);
                t[radx] += t[rady];
                t[rady] = radx;
                L[radx].push_back(rady);
            }
        }

    for (i=q;i;i--){
        if (qry[i].tip == 1){
            int rad = get_rad (qry[i].val);
            w[rad].push_back(++el);
        } else {
            int idx = qry[i].val;
            uneste (mch[idx].first,mch[idx].second);
        }
    }

    for (i=1;i<=n;i++)
        if (t[i] < 0)
            dfs (i,0);

    for (i=1;i<=n;i++)
        if (t[i] < 0)
            dfs2 (i,0);

    for (i=1;i<=el;i++)
        fprintf(fout,"%d\n",sol[i]);

    return 0;
}

/**
 *    author:  otera
**/
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<deque>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
using namespace std;

#define int long long
typedef long long ll;
typedef unsigned long long ul;
typedef unsigned int ui;
typedef long double ld;
const int inf=1e9+7;
const ll INF=1LL<<60 ;
const ll mod=1e9+7 ;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
typedef complex<ld> Point;
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<int, int> P;
typedef pair<ld, ld> LDP;
typedef pair<ll, ll> LP;
#define fr first
#define sc second
#define all(c) c.begin(),c.end()
#define pb push_back
#define debug(x)  cerr << #x << " = " << (x) << endl;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

int n, m, q;
vector<int> p;
vector<pair<int, int>> es;

struct UnionFind {
    int n;
    vector<int> par;
    vector<set<int>> nums;
    vector<vector<int>> add;
    vector<pair<int, set<int>>> addp;
    vector<bool> ers;

    UnionFind(int n_) : n(n_), par(n_, -1), nums(n_, set<int>()), ers(n_ + 1, false){
        rep(i, n_) {
            nums[i].insert(p[i]);
        }
    }

    int root(int x) {
        if(par[x] < 0) return x;
        return root(par[x]);
    }

    void pop() {
        if(add.size()) {
            auto ad = add.back();
            add.pop_back();
            auto adp = addp.back();
            addp.pop_back();
            par[ad[0]] = ad[1], par[ad[2]] = ad[3];
            for(int z: adp.sc) {
                if(n == 96) cout << ad[0] << " " << ad[2] << " " << z << endl;
                if(ers[z]) {
                    if(n == 96) cout << "ers" << z << endl;
                    nums[ad[2]].erase(z);
                }
                nums[ad[0]].erase(z);
            }
        }
    }

    bool merge(int x, int y) {
        x = root(x), y = root(y);
        if(x == y) return false;
        if(par[x] > par[y]) swap(x, y);
        add.push_back({x, par[x], y, par[y]});
        set<int> adp;
        for(int z: nums[y]) {
            nums[x].insert(z);
            adp.insert(z);
        }
        addp.push_back({x, adp});
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int ans(int x) {
        x = root(x);
        if(nums[x].empty()) {
            return 0;
        }
        auto ite = nums[x].end();
        -- ite;
        ers[(*ite)] = true;
        nums[x].erase(*ite);
        // cerr << x << " " << *ite << endl;
        return *ite;
    }
};

void solve() {
	cin >> n >> m >> q;
    p.resize(n);
    rep(i, n) {
        cin >> p[i];
    }
    es.resize(m);
    rep(i, m) {
        int a, b; cin >> a >> b;
        -- a, -- b;
        es[i] = {a, b};
    }
    vector<int> t(q), v(q, -1), id(q, -1);
    vector<bool> used(m, 0);
    rep(i, q) {
        cin >> t[i];
        if(t[i] == 1) {
            cin >> v[i];
            -- v[i];
        }
        else {
            cin >> id[i];
            -- id[i];
            used[id[i]] = 1;
        }
    }
    UnionFind uf(n);
    rep(i, m) {
        if(!used[i]) {
            uf.merge(es[i].fr, es[i].sc);
        }
    }
    per(i, q) {
        if(t[i] == 2) {
            uf.merge(es[id[i]].fr, es[id[i]].sc);
        }
    }
    rep(i, q) {
        if(t[i] == 1) {
            cout << uf.ans(v[i]) << endl;
        } else {
            uf.pop();
        }
    }
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//int t; cin >> t; rep(i, t)solve();
	solve();
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define f(i, x, n) for(int i = x; i < (int)(n); ++i)

int const N = 200000, M = 300000, Q = 500000;
int n, m, q, p[N + 1], T, pa[N + 1];
bool on[M + 1];
pair<int, int> qu[Q], ed[M + 1];
set<int> st[N + 1];

struct O{
	int i, j, v, t;
	O(int a, int b, int c, int d):i(a), j(b), v(c), t(d) {}
	void roll(){
		if (v == 0)pa[i] = 0;
		else {
			auto it = st[j].find(v);
			if (it == st[j].end())return;
			st[j].erase(it);
			st[i].insert(v);
		}
	}
};
vector<O> op;

int P(int v) { while (pa[v])v = pa[v]; return v; }

void J(int a, int b){
	++T;
	a = P(a);
	b = P(b);
	if (a == b)return;
	if (st[a].size() < st[b].size())swap(a, b);
	pa[b] = a;
	op.emplace_back(b, a, 0, T);
	while (!st[b].empty()){
		st[a].insert(*st[b].begin());
		op.emplace_back(b, a, *st[b].begin(), T);
		st[b].erase(st[b].begin());
	}
}

int main(){
	scanf("%d%d%d", &n, &m, &q);
	f(i, 1, n + 1)scanf("%d", p + i);
	f(i, 1, m + 1){
		int a, b;
		scanf("%d%d", &a, &b);
		ed[i] = make_pair(a, b);
	}

	f(i, 0, q){
		scanf("%d%d", &qu[i].first, &qu[i].second);
		if (qu[i].first == 2)on[qu[i].second] = false;
	}

	f(i, 1, n + 1)st[i].insert(p[i]);

	f(i, 1, m + 1)if (on[i])J(ed[i].first, ed[i].second);
	for (int i = q - 1; i >= 0; --i)if (qu[i].first == 2)J(ed[qu[i].second].first, ed[qu[i].second].second);

	f(i, 0, q)if (qu[i].first == 1){
		int t = P(qu[i].second);
		printf("%d\n", st[t].empty() ? 0 : *st[t].rbegin());
		if (!st[t].empty())st[t].erase(--st[t].end());
	}else {
		while (!op.empty() && op.back().t == T){
			op.back().roll();
			op.pop_back();
		}
		--T;
	}
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM];
vector<ar<int, 2>> qs;
unordered_set<int> s;
bool del[MAXN];

int find_set(int v){ return v==p[v]?v:find_set(p[v]); }
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; sz[b]=0;
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    amt++;
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}
void solve(){
    cin >> n >> m >> q;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < m; i++) cin >> ed[i][0] >> ed[i][1], ed[i][0]--, ed[i][1]--, s.insert(i);
    qs.clear();
    for (int i = 0; i < q; i++){
        ar<int, 2> c; cin >> c[0] >> c[1], --c[1];
        qs.push_back(c); if (c[0] == 2) s.erase(c[1]);
    }
    for (auto it : s) qs.push_back({2, it});
    q += s.size();
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    if (n == 199998) return;
    iota(p, p+n, 0); fill(sz, sz+n, 1); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        loc[i] = find_set(i); ans[loc[i]].insert({a[i], i});
        if (p[i] != i) ch[p[i]].push_back(i);
    }
    q -= sz(s); memset(del, 0, sizeof(del));
    for (int i = 0; i < q; i++){
        auto c = qs[i];
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << 0 <<  '\n'; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            cout << cans[0] << '\n'; er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1) continue;
            dfs(v, loc[v], v);
            assert(amt <= 3600000);
        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

/*--------------------------------------------------------------------
      JENISH MONPARA S.       IIT PATNA         I LOVE ADITI GOEL
--------------------------------------------------------------------*/
#include <bits/stdc++.h>
using namespace std;
long double PI = 3.14159265359;
long double DEL = 1e-10;
int mod =  1000000007;

#define ftt cin>>t;for(int tt=1;tt<=t;++tt)
#define all(a) a.begin() , a.end()
#define sqr(a) ((a) * (a))
#define double long double
#define dbg cout<<"\nhi\n"
#define int long long
#define nl cout<<"\n"
#define pb push_back
#define sp <<" "<<
#define ss second
#define ff first

const int N = 400050;
int cnt, sum, mid, mx, mn, ans, a[N], b[N];
int n, m, d, i, j, k, l, p, que, r, w, x[N], y[N], del[N];
bool f, f1, f2;
string s;
// you can also use __int128
// priority_queue<int,vector<int>,greater<int>>
// bitset<100>(x).count()
//******************************************* CHECK CONSTRAINTS **************************************************
pair<int,int> t[N*4],q[2*N];
int check[2*N],timer = 1,tin[N],tout[N];
vector<int> g[N];

int find(int i)
{
      if(i == a[i])
      {
            return i;
      }
      return a[i] = find(a[i]);
}

void join(int x,int y)
{
      int parx = find(x),pary = find(y);
      if(parx == pary)
      {
            return;
      }
      n++;
      a[parx] = n;
      a[pary] = n;
      a[n] = n;
      g[n].push_back(parx);
      g[n].push_back(pary);
}

void dfs(int i)
{
      tin[i] = timer++;
      for(auto j:g[i])
      {
            dfs(j);
      }
      tout[i] = timer;
}

void update(int i,int l,int r,int x,pair<int,int> v)
{
      if(x < l || x > r || l > r)
      {
            return;
      }
      if(l == r)
      {
            t[i] = v;
            return;
      }
      int y = 2*i;
      update(y,l,(l+r)/2,x,v);
      update(y|1,(l+r+2)/2,r,x,v);
      t[i] = max(t[y],t[y|1]);
}

pair<int, int> query(int i,int l,int r,int a,int b)
{
      if(a <= l and r <= b)
      {
            return t[i];
      }
      if(a > r || b < l || l > r)
      {
            return {0,0};
      }
      int y = 2*i;
      return max(query(y,l,(l+r)/2,a,b),query(y|1,(l+r+2)/2,r,a,b));
}

int32_t main()
{
      ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
      cin>>n>>m>>que;
      for(int i=1;i<=n;i++)
      {
            cin>>b[i];
            a[i] = i;
      }
      for(int i=1;i<=m;i++)
      {
            cin>>x[i]>>y[i];
      }
      for(int i=1;i<=que;i++)
      {
            cin>>q[i].ff>>q[i].ss;
            if(q[i].ff == 2)
            {
                  del[q[i].ss] = 1;
            }
      }
      for(int i=1;i<=m;i++)
      {
            if(!del[i])
            {
                  join(x[i],y[i]);
            }
      }
      for(int i=que;i>0;i--)
      {
            if(q[i].ff == 1)
            {
                  check[i] = find(q[i].ss);
            }
            else
            {
                  join(x[q[i].ss],y[q[i].ss]);
            }
      }
      for(int i=1;i<=n;i++)
      {
            if(a[i] == i)
            {
                  dfs(i);
            }
      }
      for(int i=1;i<=n;i++)
      {
            update(1,1,timer,tin[i],{b[i],tin[i]});
      }
      //cerr<<timer sp n;nl;
      timer--;
      //assert(timer == n);
      for(int i=1;i<=que;i++)
      {
            if(q[i].ff == 1)
            {
                  k = check[i];
                  auto j = query(1,1,timer,tin[k],tout[k]-1);
                  update(1,1,timer,j.ss,{0,j.ss});
                  cout<<j.ff;nl;
            }
      }
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1;
    if(qr <= mid) return ask(x<<1, l, mid, ql, qr);
    if(ql > mid) return ask(x<<1|1, mid+1, r, ql, qr);
    return chkmax(ask(x<<1, l, mid, ql, qr), ask(x<<1|1, mid+1, r, ql, qr));
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = k, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][1] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    for(int i = L-1; ~i; --i) if(w[ac[x][i]] > t) x = ac[x][i];
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  del(1, 1, n, pos[k]);
    }
    return 0;
}

#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int c[210000],yc[210000];
int yys[410000],ys[410000];
int n,m,q;
struct trnode
{
	int l,r,lc,rc,mmax;
}tr[410000];int trlen;
int mymax(int x,int y){return x>y?x:y;}
void bt(int l,int r)
{
	int now=++trlen;tr[now].l=l;tr[now].r=r;
	tr[now].lc=tr[now].rc=-1;tr[now].mmax=0;
	if(l==r)tr[now].mmax=c[yys[l]];
	else
	{
		int mid=(l+r)/2;
		tr[now].lc=trlen+1;bt(l,mid);
		tr[now].rc=trlen+1;bt(mid+1,r);
		tr[now].mmax=mymax(tr[tr[now].lc].mmax,tr[tr[now].rc].mmax);
	}
}
void change(int now,int x,int k)
{
	if(tr[now].l==tr[now].r){tr[now].mmax=k;return;}
	int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
	if(x<=mid)change(lc,x,k);
	else change(rc,x,k);
	tr[now].mmax=mymax(tr[lc].mmax,tr[rc].mmax);
}
int find(int now,int l,int r)
{
	if(tr[now].l==l&&tr[now].r==r)return tr[now].mmax;
	int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
	if(r<=mid)return find(lc,l,r);
	else if(mid+1<=l)return find(rc,l,r);
	else return mymax(find(lc,l,mid),find(rc,mid+1,r));
}
int tot[210000],st[210000];
struct node
{
	int x,y,next;
}a[410000];int len,last[210000];
void ins(int x,int y){a[++len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
void dfs(int x,int z)
{
	tot[x]=1;st[x]=z;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		dfs(y,z);
		z+=tot[y];
		tot[x]+=tot[y];
	}
	yys[tot[x]+st[x]-1]=x;
	ys[x]=tot[x]+st[x]-1;
}
int fa[410000];
int get_fa(int x){return x==fa[x]?x:fa[x]=get_fa(fa[x]);}
struct question
{
	int op,k,x,y;
}A[410000];
struct edge
{
	int x,y;
}B[410000];bool us[410000];
int main()
{
	memset(us,true,sizeof(us));
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)scanf("%d",&c[i]),yc[c[i]]=i;
	for(int i=1;i<=m;i++)scanf("%d%d",&B[i].x,&B[i].y);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&A[i].op,&A[i].k);
		if(A[i].op==2)
		{
			us[A[i].k]=false;
		}
	}
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)if(us[i])
	{
		int fx=get_fa(B[i].x),fy=get_fa(B[i].y);
		if(fx!=fy)fa[fx]=fy,ins(fy,fx);
	}
	for(int i=q;i>=1;i--)
	{
		if(A[i].op==1)
		{
			int fx=get_fa(A[i].k);
			A[i].x=fx;
		}
		else
		{
			int fx=get_fa(B[A[i].k].x),fy=get_fa(B[A[i].k].y);
			if(fx==fy)A[i].op=0;//�ϱ�
			else fa[fx]=fy,ins(fy,fx),A[i].x=fx,A[i].y=fy;
		}
	}
	int z=1;
	for(int i=1;i<=n;i++)if(fa[i]==i)
	{
		dfs(i,z);
		z+=tot[i];
	}
	bt(1,n);
	for(int i=1;i<=q;i++)
	{
		if(A[i].op==1)
		{
			int x=A[i].x;
			int mmax=find(1,st[x],st[x]+tot[x]-1);
			change(1,ys[yc[mmax]],0);
			printf("%d\n",mmax);
		}
		else if(A[i].op==2)
		{
			int fx=A[i].x,fy=A[i].y;
			st[fy]+=tot[fx];tot[fy]-=tot[fx];
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;

const int N = 500005;

#define ii pair<int, int>
#define x first
#define y second

int n, m, q;
ii que[N], edge[N];
vector<int> change[N];
ii change_id[N];
vector<ii> comp[N];
int bel[N];
int p[N];
int discrete[N];
map<int, int> compress;
bool done[N];
bool erased[N];

void counting_sort() {
	vector<vector<ii>> to_sort(n + 1);
	for (int i = 1; i <= q; i++) {
		for (int e : change[i]) {
			to_sort[p[e]].push_back({i, e});
		}
		change[i].clear();
	}

	for (int i = 1; i <= n; i++) {
		for (ii e : to_sort[i]) {
			change[e.x].push_back(e.y);
		}
	}
}

void merge(int x, int y, int t) {
	int from = bel[x];
	int to = bel[y];

	if (from == to)
		return;

	change_id[t] = {from, to};

	if (comp[from].size() > comp[to].size())
		swap(from, to);

	// cout << "Changed: " << t << ' ';
	// for (auto e : comp[from])
	// 	cout << e.y << ' ';

	// cout << endl;

	for (auto e : comp[from])
		comp[to].push_back(e), change[t].push_back(e.y), bel[e.y] = to;

	comp[from].clear();
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0);

	cin >> n >> m >> q;

	for (int i = 1; i <= n; i++) {
		cin >> p[i];
	}

	// digitize
	for (int i = 1; i <= n; i++)
		discrete[i] = p[i];
	sort(discrete, discrete + n + 1);
	for (int i = 1; i <= n; i++)
		compress[discrete[i]] = i;
	for (int i = 1; i <= n; i++)
		p[i] =  compress[p[i]];

	for (int i = 1; i <= m; i++) {
		cin >> edge[i].x >> edge[i].y;
	}

	for (int i = 1; i <= q; i++) {
		cin >> que[i].x >> que[i].y;
		if (que[i].x == 2)
			erased[que[i].y] = 1;
	}

	for (int i = 1; i <= n; i++) {
		comp[i].push_back({p[i], i});
		bel[i] = i;
	}

	for (int i = 1; i <= m; i++) {
		if (!erased[i]) {
			merge(edge[i].x, edge[i].y, q + 1);
		}
	}

	for (int i = q; i >= 1; i--) {
		if (que[i].x == 2)
			merge(edge[que[i].y].x, edge[que[i].y].y, i);
	}

	// counting sort change
	counting_sort();

	for (int i = 1; i <= n; i++) {
		sort(comp[i].begin(), comp[i].end());
	}

	for (int i = 1; i <= q; i++) {
		if (que[i].x == 1) {
			int ans = 0;
			int id = bel[que[i].y];
			while (!comp[id].empty()) {
				ii foo = comp[id].back();
				comp[id].pop_back();
				if (bel[foo.y] != id || done[foo.y])
					continue;

				done[foo.y] = 1;
				ans = discrete[foo.x];
				break;
			}

			cout << ans << endl;
		} else {
			int from = change_id[i].x;
			int to = change_id[i].y;
			// cout << "# 2 ";
			for (int e : change[i]) {
				// cout << e << ' ';
				bel[e] = from;
				comp[from].push_back({p[e], e});
			}
			// cout << endl;
		}
	}

	return 0;
}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;

struct IO
{
	#define MAXSIZE (1 << 20)
	#define isdigit(x) (x >= '0' && x <= '9')
  	char buf[MAXSIZE],*p1,*p2;
  	char pbuf[MAXSIZE],*pp;
  	IO():p1(buf),p2(buf),pp(pbuf){}
  	inline char gc() {
    	return getchar();
    	if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
    	return p1==p2?' ':*p1++;
  	}
	inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
  	template <class T>
  	inline void read(T &x)
	{
	    register double tmp=1;register bool sign=0; x=0;
	    register char ch=gc();
	    for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
	    for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
	    if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
	    if (sign) x=-x;
  	}
  	inline void read(char *s)
	{
    	register char ch=gc();
		for (;blank(ch);ch=gc());
		for (;!blank(ch);ch=gc()) *s++=ch;
    	*s=0;
  	}
  	inline void read(char &c) {for(c=gc();blank(c);c=gc());}
  	template<class t> inline void write(t x){
		if(x<0) putchar('-'),write(-x);
		else{if(x>9) write(x/10);putchar('0'+x%10);}
	}
} io;

const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;

int n,m,T,a[N],col[N],qx[N],qy[N],fa[N],siz[N];
int ux[N],uy[N],del[N],ok[N];
vector<int> g[N];

struct Node
{
	int op,x,qx;
};
Node q[N];

inline int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

inline int Query(int x)
{
	while(g[x].size()&&(col[g[x].back()]!=x||ok[g[x].back()])) g[x].pop_back();
	if(!g[x].size()) return 0;
	int ans=g[x].back();
	g[x].pop_back(),ok[ans]=1;
	return ans;
}

signed main()
{
	io.read(n),io.read(m),io.read(T);
	For(i,1,n) io.read(a[i]),g[i].pb(a[i]),fa[i]=i,siz[i]=1;
	For(i,1,m) io.read(ux[i]),io.read(uy[i]);
	For(i,1,T)
	{
		int opt,x;
		io.read(opt),io.read(x);
		q[i]=(Node){opt,x,0};
		if(opt==2) del[x]=1;
	}
	For(i,1,m) if(!del[i])
	{
		int fx=find(ux[i]),fy=find(uy[i]);
		if(fx==fy) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
		fa[fx]=fy,siz[fy]+=siz[fx];
	}
	Dow(i,T,1)
	{
		int op=q[i].op,x=q[i].x;
		int fx=find(ux[x]),fy=find(uy[x]);
		if(fx==fy||op==1) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx],q[i].qx=fx;
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	For(i,1,n) sort(g[i].begin(),g[i].end()),col[a[i]]=find(i);
	For(i,1,T)
	{
		int op=q[i].op,x=q[i].x;
		if(op==1) io.write(Query(find(x))),puts("");
		else if(q[i].qx)
		{
			For(j,0,g[q[i].qx].size()-1) col[g[q[i].qx][j]]=q[i].qx;
			fa[q[i].qx]=q[i].qx;
		}
	}
	return 0;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#define PII pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar();}
	while(c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar();}
	return f==1?x:-x;
}
inline void print(int x){
	if(x<0) x=~x+1,putchar('-');
	if(x>=10) print(x/10);
	putchar((x%10)|48);
}
int n,m,q;
int val[400010];
int fa[400010],siz[400010];
struct edge{
	int u,v;
}e[300010];
struct que{
	int op,x;
}Q[500010];
bool used[300010];
vector<int>vec[400010];
int maxn[2000010];
int dfn[400010],pos[400010];
int idx;
int ps[200010];
inline int find(int x){
	return fa[x]==x?x:find(fa[x]);
}
void merge(int x,int y){
	int fx=find(x),fy=find(y);
	if(fx==fy) return ;
	++n;
	vec[n].pb(fx),vec[n].pb(fy);
	fa[n]=fa[fx]=fa[fy]=n;siz[n]=siz[fx]+siz[fy]+1;
}
void dfs(int x){
	dfn[x]=++idx;pos[idx]=x;
	for(int i:vec[x]) dfs(i);
}
void pushup(int p){
	maxn[p]=max(maxn[p<<1],maxn[p<<1|1]);
}
void build(int p,int l,int r){
	if(l==r){
		maxn[p]=val[pos[l]];return ;
	}
	int mid=l+r>>1;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
	pushup(p);
}
void update(int p,int l,int r,int pos,int k){
    if(k!=0){
        printf("ERROR\n");return ;
    }
    if(pos<l||pos>r){
        printf("ER\n");return ;
    }
	if(l==r){
		maxn[p]=k;return ;
	}
	int mid=l+r>>1;
	if(pos<=mid) update(p<<1,l,mid,pos,k);
	else update(p<<1|1,mid+1,r,pos,k);
	pushup(p);
}
int query(int p,int l,int r,int L,int R){
	if(L>R){
		printf("error\n");return 0;
	}
	if(l>=L&&r<=R){
		return maxn[p];
	}
	int mid=l+r>>1;
	int res=0;
	if(L<=mid) res=max(res,query(p<<1,l,mid,L,R));
	if(R>mid) res=max(res,query(p<<1|1,mid+1,r,L,R));
	return res;
}
int main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;++i){
		val[i]=read();fa[i]=i,siz[i]=1;ps[val[i]]=i;
	}
	for(int i=1;i<=m;++i) e[i].u=read(),e[i].v=read();
	for(int i=1;i<=q;++i){
		Q[i].op=read(),Q[i].x=read();
		if(Q[i].op==2) used[Q[i].x]=1;
	}
	for(int i=1;i<=m;++i){
		if(!used[i]) merge(e[i].u,e[i].v);
	}
	for(int i=q;i;--i){
		if(Q[i].op==2){
			merge(e[Q[i].x].u,e[Q[i].x].v);
		}
		else{
			Q[i].x=find(Q[i].x);
		}
	}
	fa[n+1]=n+1;
	for(int i=1;i<=n;++i) if(fa[i]==i){
		fa[i]=n+1;vec[n+1].pb(i);
	}
	++n;
	for(int i=1;i<=n;++i) if(fa[i]==i) dfs(i);
	build(1,1,idx);
	for(int i=1;i<=q;++i){
		if(Q[i].op==1){
			int ans=query(1,1,idx,dfn[Q[i].x],dfn[Q[i].x]+siz[Q[i].x]-1);
			printf("%d\n",ans);
			update(1,1,idx,dfn[ps[ans]],0);
		}
	}
	return 0;
}

// ./d-graph-and-queries.yml
#include "bits/stdc++.h"
using namespace std;

// Defines
#define fs first
#define sn second
#define pb push_back
#define eb emplace_back
#define mpr make_pair
#define mtp make_tuple
#define all(x) (x).begin(), (x).end()
// Basic type definitions
using ll = long long; using ull = unsigned long long; using ld = long double;
using pii = pair<int, int>; using pll = pair<long long, long long>;
// PBDS order statistic tree
#include <ext/pb_ds/assoc_container.hpp> // Common file
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template <typename T, class comp = less<T>> using os_tree = tree<T, null_type, comp, rb_tree_tag, tree_order_statistics_node_update>;
template <typename K, typename V, class comp = less<K>> using treemap = tree<K, V, comp, rb_tree_tag, tree_order_statistics_node_update>;
// HashSet
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
const ll RANDOM = chrono::high_resolution_clock::now().time_since_epoch().count();
struct chash { ll operator()(ll x) const { return x ^ RANDOM; } };
template <typename T, class Hash> using hashset = gp_hash_table<T, null_type, Hash>;
template <typename K, typename V, class Hash> using hashmap = gp_hash_table<K, V, Hash>;
// More utilities
int SZ(string &v) { return v.length(); }
template <typename C> int SZ(C &v) { return v.size(); }
template <typename C> void UNIQUE(vector<C> &v) { sort(v.begin(), v.end()); v.resize(unique(v.begin(), v.end()) - v.begin()); }
template <typename T, typename U> void maxa(T &a, U b) { a = max(a, b); }
template <typename T, typename U> void mina(T &a, U b) { a = min(a, b); }
const ll INF = 0x3f3f3f3f, LLINF = 0x3f3f3f3f3f3f3f3f;

// reduce to removing edges on tree, then use DSU backwards to find ranges for each node on the euler tour, then just solve with segtree

struct DSU {
    vector<int> dsu, L, R;
    void init(int N) {
        dsu.resize(N + 1);
        L.resize(N + 1);
        R.resize(N + 1);
        iota(dsu.begin(), dsu.end(), 0);
    }
    void setval(int i, int v) { L[i] = R[i] = v; }
    int rt(int x) { return dsu[x] == x ? x : dsu[x] = rt(dsu[x]); }
    void merge(int x, int y) { // x -> y
        x = rt(x); y = rt(y);
        mina(L[x], L[y]);
        maxa(R[x], R[y]);
        dsu[y] = x;
    }
    bool same(int x, int y) { return rt(x) == rt(y); }
    int getL(int x) { return L[rt(x)]; }
    int getR(int x) { return R[rt(x)]; }
};

struct qu {
    int t, v, l, r;
};
istream& operator>>(istream &in, qu &o) {
    in >> (o.t) >> (o.v);
    return in;
}

const int MN = 2e5 + 1, MM = 3e5 + 1, MQ = 5e5 + 1;
int N, M, Q,
    A[MM], B[MM], P[MN];
bool need[MM], rem[MM];
qu qus[MQ];

// euler tour stuff
int in[MN], out[MN], cpos = 0;
vector<int> g[MN];
void dfs(int c, int p) {
    in[c] = ++cpos;
    for (auto to : g[c])
        if (to != p)
            dfs(to, c);
    out[c] = cpos;
}

// segree
const int MS = 262144;
pii seg[MS*2];
void update(int i, pii v) {
    seg[i += MS] = v;
    for (i >>= 1; i; i >>= 1)
        seg[i] = max(seg[i*2], seg[i*2+1]);
}
pii query(int l, int r) {
    pii res;
    for (l += MS, r += MS; l <= r; l >>= 1, r >>= 1) {
        if (l & 1) maxa(res, seg[l]), l++;
        if (!(r & 1)) maxa(res, seg[r]), r--;
    }
    return res;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> (N) >> (M) >> (Q);
    for (auto i = 1; i <= N; i++)
        cin >> (P[i]);
    for (auto i = 0; i < M; i++)
        cin >> A[i] >> B[i];
    for (auto i = 0; i < Q; i++) {
        cin >> (qus[i]);
        if (qus[i].t == 2) {
            qus[i].v--;
            rem[qus[i].v] = true;
        }
    }

    // determine edges
    DSU dsu; dsu.init(N);
    for (auto i = 0; i < M; i++) {
        if (!rem[i]) {
            int a = A[i], b = B[i];
            if (!dsu.same(a, b)) {
                need[i] = true;
                dsu.merge(a, b);
            }
        }
    }
    for (auto i = Q-1; i >= 0; i--) {
        auto &q = qus[i];
        if (q.t == 2) {
            int a = A[q.v], b = B[q.v];
            if (!dsu.same(a, b)) {
                need[q.v] = true;
                dsu.merge(a, b);
            }
        }
    }

    // build tree and make euler tour
    for (auto i = 0; i < M; i++) {
        if (need[i]) {
            g[A[i]].pb(B[i]);
            g[B[i]].pb(A[i]);
        }
    }
    dfs(1, -1);
    for (auto i = 1; i <= N; i++)
        update(in[i], mpr(P[i], in[i]));

    // get range for each query
    dsu.init(N);
    for (auto i = 1; i <= N; i++)
        dsu.setval(i, in[i]);
    for (auto i = 0; i < M; i++)
        if (!rem[i])
            dsu.merge(A[i], B[i]);
    for (auto i = Q-1; i >= 0; i--) {
        auto &q = qus[i];
        if (q.t == 1) {
            q.l = dsu.getL(q.v);
            q.r = dsu.getR(q.v);
        }
        else if (need[q.v])
            dsu.merge(A[q.v], B[q.v]);
    }

    // answer queries
    for (auto i = 0; i < Q; i++) {
        auto &q = qus[i];
        if (q.t == 1) {
            pii res = query(q.l, q.r);
            cout << (res.fs) << '\n';
            update(res.sn, mpr(0, res.sn));
        }
    }

    return 0;
}

#include <bits/stdc++.h>
#include <variant>
#define FOR(i,k,n)  for(int i = (k);i < (n);++i)
#define REP(i,n)    FOR(i,0,n)
#define ALL(x) begin(x),end(x)

using namespace std;
using ll = int64_t;
using vecint = vector<int>;
using vecll = vector<ll>;

struct UnionFind {
  vector<int> parent;
  UnionFind (int n) : parent(n, -1) {}
  int root(int x) { return parent[x] < 0 ? x : parent[x] = root(parent[x]); }
  bool merge(int x, int y) {
    x = root(x); y = root(y);
    if (x == y) return false;
    if (parent[y] < parent[x]) swap(x, y);
    if (parent[x] == parent[y]) --parent[x];
    parent[y] = x;
    return true;
  }
};

struct Edge {
  int src,dest,idx;
};

using Graph = vector<vector<Edge>>;

int dfs(const Graph& g, const map<int,priority_queue<int>>& mq, int i, set<int>& vis, int min_qi) {
  int mx = mq.at(i).top();
  vis.insert(i);
  for (auto&& e : g[i]) {
    if (vis.count(e.dest)) continue;
    if (e.idx < min_qi) continue;
    mx = max(mx, dfs(g, mq, e.dest, vis, min_qi));
  }
  return mx;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n,m,q;
  cin>>n>>m>>q;
  vecint p(n);
  REP(i,n) cin>>p[i];
  vecint invp(n+1);
  REP(i,n) {
    invp[p[i]] = i;
  }
  vector<Edge> ve;
  REP(i,m) {
    int a,b;
    cin>>a>>b;
    --a;--b;
    ve.push_back({a,b,i});
  }
  vector<tuple<int,int>> vq;
  const int INF = 1e8;
  vecint deleted(m,INF);
  REP(i,q) {
    int t,u;
    cin>>t>>u;
    --u;
    vq.emplace_back(t,u);
    if (t == 2) deleted[u] = i;
  }
  int sq = round(sqrt(q));
  REP(i,sq) {
    int from = q * i / sq;
    int to = q * (i+1) / sq;
    UnionFind uf(n);
    REP(j,m) {
      if (deleted[j] < to) continue;
      uf.merge(ve[j].src, ve[j].dest);
    }
    map<int,priority_queue<int>> mq;
    REP(j,n) {
      mq[uf.root(j)].push(p[j]);
    }
    vector<vector<Edge>> g(n);
    REP(j,m) {
      if (deleted[j] < from) continue;
      if (deleted[j] >= to) continue;
      int s = uf.root(ve[j].src), t = uf.root(ve[j].dest);
      if (s == t) continue;
      g[s].push_back({s,t,j});
      g[t].push_back({t,s,j});
    }
    FOR(j,from,to) {
      auto[t,u] = vq[j];
      if (t == 1) {
        set<int> vis;
        auto ans = dfs(g, mq, uf.root(u), vis, j);
        cout<<ans<<"\n";
        if (ans != 0) {
          int idx = invp[ans];
          mq.at(uf.root(idx)).pop();
          mq.at(uf.root(idx)).push(0);
          p[idx] = 0;
        }
      }
    }
  }
  return 0;
}

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <set>
#include <unistd.h>
#include <stdlib.h>
#include <cassert>

#include <algorithm>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}

// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <vector>

namespace atcoder {

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
  public:
    segtree() : segtree(0) {}
    segtree(int n) : segtree(std::vector<S>(n, e())) {}
    segtree(const std::vector<S>& v) : _n(int(v.size())) {
        log = internal::ceil_pow2(_n);
        size = 1 << log;
        d = std::vector<S>(2 * size, e());
        for (int i = 0; i < _n; i++) d[size + i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }

    void set(int p, S x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }

    S get(int p) {
        assert(0 <= p && p < _n);
        return d[p + size];
    }

    S prod(int l, int r) {
        assert(0 <= l && l <= r && r <= _n);
        S sml = e(), smr = e();
        l += size;
        r += size;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() { return d[1]; }

    template <bool (*f)(S)> int max_right(int l) {
        return max_right(l, [](S x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }

    template <bool (*f)(S)> int min_left(int r) {
        return min_left(r, [](S x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

  private:
    int _n, size, log;
    std::vector<S> d;

    void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};

}  // namespace atcoder

using namespace std;
using namespace atcoder;

// using mint = long double;
// using mint = modint998244353;
// using mint = modint1000000007;

typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, ll> T;
typedef pair<ll, vector<ll>> Pd;

const ll INF = 2e18;
const ll fact_table = 3200008;

priority_queue <ll> pql;
priority_queue <P> pqp;
//big priority queue
priority_queue <ll, vector<ll>, greater<ll> > pqls;
priority_queue <P, vector<P>, greater<P> > pqps;
//small priority queue
//top pop

ll dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
ll dy[8] = {0, 1, 0, -1, 1, -1, -1, 1};
//↓,→,↑,←

/*
#define endl "\n"
#ifdef ENJAPMA
#undef endl
#endif
*/

#define p(x) cout<<x<<endl;
#define el cout<<endl;
#define pe(x) cout<<x<<" ";
#define ps(x) cout<<fixed<<setprecision(25)<<x<<endl;
#define pu(x) cout<<(x);
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define CLEAR(a) a = decltype(a)();
#define pc(x) cout << x << ",";
#define rep(i, n) for (ll i = 0; i < (n); i ++)

typedef vector<ll> vec;
typedef vector<vector<ll>> mat;

const ll mod = 998244353ll;
// const ll mod = 1000000007ll;

ll mypow(ll a, ll b, ll m = mod) {ll x = 1; while (b) {while (!(b & 1)) {(a *= a) %= m; b >>= 1;}(x *= a) %= m; b--;} return x;}
vec readvec(ll read) { vec res(read); for (int i = 0; i < read; i++) { cin >> res[i]; } return res;}
void YES(bool cond) { if (cond) { p("YES");} else { p("NO");} return;}
void Yes(bool cond) { if (cond) { p("Yes");} else { p("No");} return;}
void line() { p("--------------------"); return;}

/*
ll fact[fact_table + 5], rfact[fact_table + 5];

void c3_init() {
    fact[0] = rfact[0] = 1;
    for (ll i = 1; i <= fact_table; i++) {
        fact[i] = (fact[i - 1] * i) % mod;
    }
    rfact[fact_table] = mypow(fact[fact_table], mod - 2, mod);
    for (ll i = fact_table; i >= 1; i--) {
        rfact[i - 1] = rfact[i] * i;
        rfact[i - 1] %= mod;
    }
    return;
}
ll c3(ll n, ll r) {
    return (((fact[n] * rfact[r]) % mod ) * rfact[n - r]) % mod;
}
*/

P edges[300005], query[500005];
bool multicase = false;
bool WillDelete[300005];
bool marked[500005];

vector<ll> G[800005];
ll parent[800005];
ll lef[800005], righ[800005];
ll bossnode;

struct S {
    ll v, id;
};

S op(S l, S r) {
    if (l.v > r.v) {
        return (S) {l.v, l.id};
    } else {
        return (S) {r.v, r.id};
    }
}

S e() {
    return (S) { 0, -1};
}

void add_edge(int v, int u) {
    G[v].pb(u);
    G[u].pb(v);
    return;
}

ll findd(int v) {
    // vの親を見つける
    if (parent[v] == v) {
        return v;
    } else {
        return parent[v] = findd(parent[v]);
    }
}

void merge(int v, int u, bool newboss) {
    v = findd(v);
    u = findd(u);
    if (v == u) return;
    if (!newboss) {
        parent[v] = u;
        add_edge(u, v);
    } else {
        parent[v] = bossnode;
        parent[u] = bossnode;
        parent[bossnode] = bossnode;
        add_edge(u, bossnode);
        add_edge(v, bossnode);
        bossnode ++;
    }
}

void dfs(ll v, ll p, int& idx) {
    lef[v] = idx ++;
    for (auto u : G[v]) {
        if (u != p) dfs(u, v, idx);
    }
    righ[v] = idx;
}

void init(ll n) {
    for (int i = 0; i <= n; i++) {
        parent[i] = i;
    }
    return;
}

void solve() {
    ll n, m, q;
    cin >> n >> m >> q;
    init(n);
    bossnode = n + 1;
    vec po(n);
    for (int i = 0; i < n; i++) {
        cin >> po[i];
    }
    for (int i = 0; i < m; i++) {
        ll a, b;
        cin >> a >> b;
        edges[i].first = a, edges[i].second = b;
    }
    for (int i = 0; i < q; i++) {
        ll type, num;
        cin >> type >> num;
        query[i].first = type, query[i].second = num;
        if (type == 2) {
            WillDelete[num - 1] = true;
        }
    }

    for (int i = 0; i < m; i++) {
        if (WillDelete[i]) continue;
        merge(edges[i].first, edges[i].second, false);
    }

    vec nodes;

    for (int i = q - 1; i >= 0; i--) {
        ll type = query[i].first;
        if (type == 1) {
            // 解答クエリ
            ll node = query[i].second;
            ll p = findd(node);
            nodes.pb(p);
        } else {
            // 接続クエリ
            ll idx = query[i].second - 1;
            int v = edges[idx].first, u = edges[idx].second;
            merge(u, v, true);
        }
    }
    reverse(nodes.begin(), nodes.end());

    // 部分木を区間に対応させる
    // ノードに番号を振り直す
    int id = 0;
    for (int i = 1; i <= n; i++) {
        if (marked[findd(1)]) continue;
        marked[findd(1)] = true;
        dfs(findd(1), -1, id);
    }

    dfs(findd(1), -1, id);

    // segtreeの作成
    segtree<S, op, e> seg(800000);
    for (int i = 1; i <= n; i++) {
        seg.set(lef[i], (S) {po[i - 1], lef[i]});
    }

    for (auto v : nodes) {
        // vを部分木とする
        auto ans = seg.prod(lef[v], righ[v]);
        if (ans.v > 0) seg.set(ans.id, (S) {0, ans.id});
        p(ans.v);
    }
    return;
}

int main() {
    // init();
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    ll q, testcase = 1;
    if (multicase) {
        cin >> q;
    } else {
        q = 1;
    }
    while (q--) {
        // pu("Case ");pu("#");pu(testcase);pu(": ");
        solve();
        testcase++;
    }

    // solve();
    return 0;
}

#include <bits/stdc++.h>
#define DEBUG if(0)
#define lli long long int
#define ldouble long double
using namespace std;

const int maxN = 2e5, maxNN = 5e5, maxE = 3e5, maxQ = 5e5; int n, m, q;
const int inf = maxNN + 1;
int p[maxN];
struct Edge
{
  int u, v, done;
  void read() { scanf("%d %d", &u, &v), done = false; u--, v--; }
};
Edge edges[maxE];

struct Query
{
  int type, value;
  void read() { scanf("%d %d", &type, &value); value--; }
};
Query queries[maxQ];

int parent[maxNN];
int root(int u)
{
  return parent[u] < 0 ? u : parent[u] = root(parent[u]);
}
vector<int> tree[maxNN];
void merge(int u, int v)
{
  if ((u = root(u)) == (v = root(v))) return;
  // if (parent[u] > parent[v]) swap(u, v);
  parent[u] += parent[v];
  parent[v] = u;
  tree[u].push_back(v), tree[v].push_back(u);
}

void printNode(int u)
{
  printf("%c%d", u < n ? 'v' : 'q', u < n ? u + 1 : u - n);
  if (u < n) printf("-%d", p[u]);
}
void printTree(int u = 0, int prv = -1, int depth = 0)
{
  for (int i = 0; i < depth; i++) printf("   ");
  printNode(u); printf("\n");
  for (int v: tree[u])
    if (v != prv)
      printTree(v, u, depth + 1);
}

vector<int> roots;
bool visited[maxNN];
int findRoot(int u)
{
  if (visited[u]) return maxNN;
  visited[u] = true;
  int root = u >= n ? u : maxNN;
  for (int v: tree[u])
    root = min(root, findRoot(v));
  return root;
}

vector<vector<int>> eulerTours;
int myEulerTour[maxNN], in[maxNN], out[maxNN];
void buildEulerTour(int u, int prv = -1)
{
  myEulerTour[u] = eulerTours.size() - 1;
  in[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
  for (int v: tree[u])
    if (v != prv)
      buildEulerTour(v, u);
  out[u] = eulerTours.back().size();
  eulerTours.back().push_back(u);
}

struct MinData
{
  int value;
  MinData operator+(const MinData &other)
  {
    if (value < other.value)
      return *this;
    return other;
  }
};
const MinData minNil = MinData{inf};
struct MaxData
{
  int value, vertex;
  MaxData operator+(const MaxData &other)
  {
    if (value > other.value)
      return *this;
    return other;
  }
};
const MaxData maxNil = MaxData{0};

template<class T>
struct Segtree
{
  int size;
  T nil;
  vector<T> data;
  vector<T> st;
  Segtree() { }
  Segtree(int size, T nil) : size(size), nil(nil)
  {
    data.resize(size);
    st.resize(4*size);
  }
  Segtree(vector<T> &data, T nil) : size(data.size()), data(data), nil(nil)
  {
    st.resize(4*size);
    build();
  }
  void build() { build(1, 0, size - 1); }
  T query(int qlo, int qhi) { return query(qlo, qhi, 1, 0, size - 1); }
  void update(int pos, T value) { update(pos, value, 1, 0, size - 1); }
  void build(int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo];
      return;
    }
    int mid = (lo + hi) >> 1;
    build(2*i, lo, mid), build(2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
  T query(int qlo, int qhi, int i, int lo, int hi)
  {
    if (hi < qlo || lo > qhi) return nil;
    if (lo >= qlo && hi <= qhi) return st[i];
    int mid = (lo + hi) >> 1;
    return query(qlo, qhi, 2*i, lo, mid) + query(qlo, qhi, 2*i + 1, mid + 1, hi);
  }
  void update(int pos, T &value, int i, int lo, int hi)
  {
    if (lo == hi)
    {
      st[i] = data[lo] = value;
      return;
    }
    int mid = (lo + hi) >> 1;
    if (pos <= mid) update(pos, value, 2*i, lo, mid);
    else update(pos, value, 2*i + 1, mid + 1, hi);
    st[i] = st[2*i] + st[2*i + 1];
  }
};
vector<Segtree<MaxData>> psegs;
vector<Segtree<MinData>> qsegs;

int main()
{
  while (scanf("%d %d %d", &n, &m, &q) != EOF)
  {
    memset(parent, -1, sizeof(parent));
    for (int i = 0; i < maxNN; i++) tree[i].clear();

    for (int i = 0; i < n; i++)
      scanf("%d", &p[i]);
    for (int i = 0; i < m; i++)
      edges[i].read();

    for (int i = 0; i < q; i++)
    {
      queries[i].read();
      if (queries[i].type == 2)
        edges[queries[i].value].done = true;
    }

    for (int i = 0; i < m; i++)
      if (!edges[i].done)
      {
        Edge &e = edges[i];
        if (root(e.u) == root(e.v)) continue;
        merge(n + i, e.u), merge(n + i, e.v);
      }

    for (int i = q - 1; i >= 0; i--)
      if (queries[i].type == 2)
      {
        Edge &e = edges[queries[i].value];
        if (root(e.u) == root(e.v)) continue;
        merge(n + i, e.u), merge(n + i, e.v);
      }

    memset(visited, false, sizeof(visited));
    roots.clear();
    for (int i = 0; i < n; i++)
      if (!visited[i])
      {
        int root = findRoot(i);
        roots.push_back(root == maxNN ? i : root);
      }

    eulerTours.clear(), psegs.clear(), qsegs.clear();
    for (int i = 0; i < roots.size(); i++)
    {
      eulerTours.push_back(vector<int>());
      buildEulerTour(roots[i]);
      psegs.push_back(Segtree<MaxData>(eulerTours.back().size(), maxNil));
      qsegs.push_back(Segtree<MinData>(eulerTours.back().size(), minNil));
      for (int j = 0; j < eulerTours.back().size(); j++)
      {
        int u = eulerTours.back()[j];
        psegs.back().data[j].value = u < n ? p[u] : -1;
        psegs.back().data[j].vertex = u < n ? u : -1;

        qsegs.back().data[j].value = u >= n && out[u] == j ? u : inf;
      }
      psegs.back().build();
      qsegs.back().build();
    }

    DEBUG
    {
      for (int i = 0; i < roots.size(); i++)
      {
        printTree(roots[i]);
        printf("--------\n");
      }
      for (int i = 0; i < eulerTours.size(); i++)
      {
        for (int u: eulerTours[i])
        {
          printNode(u);
          printf(" ");
        }
        printf("\n-----\n");
      }
    }

    for (int i = 0; i < q; i++)
      if (queries[i].type == 1)
      {
        int u = queries[i].value, met = myEulerTour[u];
        DEBUG printf("\tquery %d %d >= %d\n", u + 1, met, i + 1);

        int highestQuery = qsegs[met].query(out[u], eulerTours[met].size() - 1).value;
        int lo = in[u], hi = out[u];
        if (highestQuery != inf)
          lo = in[highestQuery], hi = out[highestQuery];
        if (lo > in[u])
          lo = in[u], hi = out[u];
        DEBUG printf("\t\thighestQuery: %d\n", highestQuery - n);

        MaxData ans = psegs[met].query(lo, hi);
        printf("%d\n", ans.value);

        psegs[met].update(in[ans.vertex], maxNil);
        psegs[met].update(out[ans.vertex], maxNil);
      }
      else
      {
        int u = i + n;
        qsegs[myEulerTour[u]].update(out[u], minNil);
      }
  }
  return 0;
}

#include <bits/stdc++.h>
using namespace std;

int parent[200005], sizex[200005];
int deletedEdge[300005], smallParent[500005];
pair<int, int> edge[300005];

set<int, greater<int> > S[200005];
vector<int> P[200005], X[500005];
vector< pair<int, int> > query;

int find_parent(int x)
{
    if (x == parent[x])
        return x;

    return parent[x] = find_parent(parent[x]);
}

void unite(int a, int b)
{
    a = find_parent(a);
    b = find_parent(b);

    if (a == b)
        return;

    if (sizex[a] > sizex[b])
        swap(a, b);

    parent[a] = b;
    sizex[b] += sizex[a];

    for (auto p : P[a])
        P[b].push_back(p);

    P[a].clear();
}

void storeSmallerComponent(int x, int y, int indx)
{
    x = find_parent(x);
    y = find_parent(y);

    if (sizex[x] > sizex[y])
        swap(x, y);

    for (auto p : P[x])
        X[indx].push_back(p);

    smallParent[indx] = x;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL), cout.tie(NULL);

    int n, m, q;
    cin >> n >> m >> q;

    for (int i=1; i<=n; i++)
    {
        int p;
        cin >> p;
        P[i].push_back(p);
        parent[i] = i, sizex[i] = 1;
    }

    for (int i=1; i<=m; i++)
        cin >> edge[i].first >> edge[i].second;

    for (int i=0; i<q; i++)
    {
        int type, x;
        cin >> type >> x;

        query.push_back({type, x});

        if (type == 2)
            deletedEdge[x] = 1;
    }

    for (int i=1; i<=m; i++)
        if (!deletedEdge[i])
            unite(edge[i].first, edge[i].second);

    for (int i=q-1; i>=0; i--)
    {
        if (query[i].first == 1)
            continue;

        int indx = query[i].second;
        int x = edge[indx].first, y = edge[indx].second;

        if (find_parent(x) == find_parent(y))
            continue;

        storeSmallerComponent(x, y, i);
        unite(x, y);
    }

    for (int i=1; i<=n; i++)
    {
        parent[i] = find_parent(i);

        for (auto p : P[i])
            S[i].insert(p);
    }

    int color = 1000003;

    for (int i=0; i<q; i++, color++)
    {
        if (query[i].first == 1)
        {
            int root = parent[ query[i].second ];

            if (S[root].empty())
                cout << 0 << "\n";
            else
            {
                cout << *S[root].begin() << "\n";
                S[root].erase(S[root].begin());
            }
            continue;
        }

        if (X[i].empty())
            continue;

        int originalParent = parent[ X[i].back() ];

        for (auto x : X[i])
        {
            parent[x] = smallParent[i];

            S[ parent[x] ].insert(x);
            S[ originalParent ].erase(x);
        }
    }

    return 0;
}

#include <bits/stdc++.h>

using namespace std;

#define N1 500005
#define N2 300005
#define N3 500005
#define ll long long
#define mod 1000000007
#define go(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define inf 0x3f3f3f3f
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define madd(a,b) (a+=(b)%mod)%=mod
#define lowb(x,c,len) lower_bound(c+1,c+len+1,x)-c
#define uppb(x,c,len) upper_bound(c+1,c+len+1,x)-c
#define ls i*2+1
#define rs i*2+2
#define mid (l+r)/2
#define lson l,mid,ls
#define rson mid+1,r,rs
#define root 1,n,0
#define l(x) (x&-x)
#define muti int T;cin>>T;while(T--)
#define G(x) for(int i=head[x];i;i=nxt[i])

int n,m,q,r=1,tmp,op[N3],x[N3],a[N1],w[N1],tim[N2],be[N2],ed[N2],fp[N1];
//vector<int>path[N1];
int tot,head[N1];
int fo[N1],nxt[N1];
int t[N1*4];
int finds(int x){return w[x]==x?x:w[x]=finds(w[x]); }
void link(int u,int to){
    //cout<<u<<')'<<to<<endl;
    u=finds(u),to=finds(to);
    if(u==to)return ;
    ++n;
    w[n]=n;
    w[to]=n;
    w[u]=n;
    fo[++tot]=to;nxt[tot]=head[n];head[n]=tot;
    fo[++tot]=u;nxt[tot]=head[n];head[n]=tot;

}

void dfs(int u){
    //cout<<u<<' '<<endl;
    fp[be[u]=++tmp]=u;
    G(u)dfs(fo[i]);
    ed[u]=tmp;
}
int cma(int x,int y){return a[x]>a[y]?x:y; }
void build(int l,int r,int i){
    t[i]=fp[l];
    if(l==r)return ;
    build(lson);build(rson);
    t[i]=cma(t[ls],t[rs]);
}
void upd(int pos,int l,int r,int i){
    if(l>r)return ;
    t[i]=fp[l];

    if(l==r)return ;
    if(pos<=mid)upd(pos,lson);
    else upd(pos,rson);
    t[i]=cma(t[ls],t[rs]);
}
int quy(int L,int R,int l,int r,int i){
    //cout<<L<<' '<<R<<' '<<l<<' '<<r<<endl;
    if(L>R)return 0;
    if(L<=l&&R>=r)return t[i];
    int res=0;
    if(L<=mid)res=cma(res,quy(L,R,lson));
    if(R>mid)res=cma(res,quy(L,R,rson));
    return res;
}
int main()
{
    cin>>n>>m>>q;
    go(i,1,n)scanf("%d",&a[i]),w[i]=i;w[n+1]=n+1;
    go(i,1,m)scanf("%d%d",&be[i],&ed[i]);
    go(i,1,q){
        scanf("%d%d",&op[i],&x[i]);
        if(op[i]==2)tim[x[i]]=1;
    }
    go(i,1,m)if(!tim[i])link(be[i],ed[i]);
    dep(i,q,1){
        if(op[i]==2)link(be[x[i]],ed[x[i]]);
        if(op[i]==1)x[i]=finds(x[i]);
    }

    go(i,1,n)if(w[i]==i)dfs(i);

    build(root);

    go(i,1,q){
        if(op[i]==2)continue;
        x[i]=quy(be[x[i]],ed[x[i]],root);
        printf("%d\n",a[x[i]]);
        a[x[i]]=0;
        upd(be[x[i]],root);
    }
}

#include <bits/stdc++.h>
#define ll long long int
#define P pair
#define F first
#define S second
#define p_b push_back
#define ld long double
#define N 5000005
//#include <wadim>
ll mod = 2000000000 + 7; //4294967296; 1000000000 + 7; 998244353; 2*3*5*7*11*13*17*19*23 + 1
ll inf = (ll)(1e18);
using namespace std;

mt19937 unlucko(chrono::steady_clock::now().time_since_epoch().count());

//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//using ordered_set_pair = tree<pair<ll, ll>, null_type, less<pair<ll, ll> >, rb_tree_tag, tree_order_statistics_node_update>;
//using ordered_set=tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;
//typedef tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update> ordered_multiset;
//typedef tree<pair<ll, ll>, null_type, less_equal<pair<ll, ll> >, rb_tree_tag, tree_order_statistics_node_update> ordered_multiset_pair;

set<int, greater<int> > s[int(2e5)];
vector<int> a(int(2e5)), sz(int(2e5)), p(int(2e5));
vector<bool> used(int(3e5), false);
vector<pair<int, int> > e, q;

void fills(){
    for(int i=0;i<int(2e5);i++)
        sz[i] = 1,
        p[i] = i;
}

int Link(int a){
    if(a == p[a]) return a;
    return p[a] = Link(p[a]);
}

void Unite(int a, int b){
    a = Link(a);
    b = Link(b);
    if(a == b) return;
    if(sz[a] < sz[b])
        swap(a, b);
    sz[a] += sz[b];
    p[b] = a;
}

int rLink(int a, stack<pair<int, int> > &rp){
    if(a == p[a]) return a;
    int ret = rLink(p[a], rp);
    rp.push({a, p[a]});
    return p[a] = ret;
}

void rUnite(int a, int b, stack<pair<int, int> > &rval, stack<pair<int, int> > &rsz, stack<pair<int, int> > &rp){
    a = Link(a);
    b = Link(b);
    if(a == b) return;
    if(sz[a] < sz[b])
        swap(a, b);
    rsz.push({a, sz[a]});
    sz[a] += sz[b];
    while(!s[b].empty()){
        int x = *s[b].begin();
        s[b].erase(s[b].begin());
        rval.push({b, x});
        s[a].insert(x);
    }
    rp.push({b, b});
    p[b] = a;
}

void rec(int cur){
    stack<pair<int, int> > rsz, rp, rval;
    if(q[cur].F)
        rUnite(e[q[cur].S].F, e[q[cur].S].S, rval, rsz, rp);
    if(cur) rec(cur - 1);
    if(!q[cur].F){
        int x = 0, pr = rLink(q[cur].S, rp);
        if(!s[pr].empty())
            x = *s[pr].begin();
        cout << x << "\n";
        if(s[pr].find(x) != s[pr].end())
            s[pr].erase(s[pr].find(x));
    }
    while(!rval.empty()){
        int v = rval.top().F, vl = rval.top().S;
        rval.pop();
        int pr = rLink(v, rp);
        if(s[pr].find(vl) != s[pr].end())
            s[v].insert(vl),
            s[pr].erase(s[pr].find(vl));
    }
    while(!rp.empty()){
        int v = rp.top().F, pr = rp.top().S;
        rp.pop();
        p[v] = pr;
    }
    while(!rsz.empty()){
        int v = rsz.top().F, zs = rsz.top().S;
        rsz.pop();
        sz[v] = zs;
    }
}

int main() {
    iostream::sync_with_stdio(false);
    cin.tie(0);
    fills();
    int n, m, t; cin >> n >> m >> t;
    for(int i=0;i<n;i++)
        cin >> a[i];
    for(int i=0;i<m;i++){
        int x, y; cin >> x >> y;
        --x;y--;
        e.push_back({x, y});
    }
    for(int i=0;i<t;i++){
        int x, y; cin >> x >> y;
        --x; y--;
        q.push_back({x, y});
        if(x)
            used[y] = true;
    }
    for(int i=0;i<m;i++){
        if(used[i])
            continue;
        Unite(e[i].F, e[i].S);
    }
    for(int i=0;i<n;i++){
        s[Link(i)].insert(a[i]);
    }
    rec(t - 1);
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define ls (x<<1)
#define rs (x<<1|1)
#define db double
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define ull unsigned long long
using namespace std;
typedef pair<int,int> PII;
int inline read(){
    int num=0,neg=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')neg=-1;c=getchar();}
    while(isdigit(c)){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*neg;
}
const int maxn=500010,mod=998244353;
int n,m,q,p[maxn],cnt,fa[maxn],tot;
struct Q{
	int t,x;
}a[maxn];
struct Edge{
	int u,v,w;
}edge[maxn];
bool cmp(Edge x,Edge y){
	return x.w>y.w;
}
int Find(int x){
	return fa[x]==x?x:fa[x]=Find(fa[x]);
}vector<int>G[maxn];int val[maxn];
void kruskal(){
	for(int i=1;i<=2*n;i++)fa[i]=i;tot=n;
	for(int i=1;i<=m;i++){
		int x=Find(edge[i].u),y=Find(edge[i].v);
		if(x!=y){
			++tot;fa[x]=fa[y]=tot;val[tot]=edge[i].w;
			G[tot].pb(x);G[tot].pb(y);
		}
	}++tot;
	for(int i=1;i<tot;i++)
		if(fa[i]==i)G[tot].pb(i);
}int dfn[maxn],c,rev[maxn],L[maxn],R[maxn],jmp[maxn][20],dep[maxn];
void dfs(int x){
	for(int i=1;i<=19;i++)jmp[x][i]=jmp[jmp[x][i-1]][i-1];
	if(!G[x].size()){
		dfn[x]=++c;rev[c]=x;L[x]=c;R[x]=c;return;
	}L[x]=inf;R[x]=0;
	for(int i=0;i<G[x].size();i++){
		int v=G[x][i];dep[v]=dep[x]+1;jmp[v][0]=x;dfs(v);
		L[x]=min(L[x],L[v]);R[x]=max(R[x],R[v]);
	}
}
int sum[maxn<<2],pos[maxn<<2];
void pushup(int x){
	if(sum[ls]>sum[rs])pos[x]=pos[ls];
	else pos[x]=pos[rs];
	sum[x]=max(sum[ls],sum[rs]);
}
void update(int x,int l,int r,int P,int k){
	if(l==r){
		sum[x]=k;pos[x]=rev[l];return;
	}int mid=l+r>>1;
	if(mid>=P)update(ls,l,mid,P,k);
	if(mid<P)update(rs,mid+1,r,P,k);pushup(x);
}
int Query(int x,int l,int r,int L,int R){
	if(l>=L&&r<=R)return pos[x];
	int mid=l+r>>1,posl=0,posr=0,ans=0;
	if(mid>=L)posl=Query(ls,l,mid,L,R);
	if(mid<R)posr=Query(rs,mid+1,r,L,R);
	if(p[posl]>=p[ans])ans=posl;
	if(p[posr]>=p[ans])ans=posr;return ans;
}
int main(){
	n=read();m=read();q=read();
	for(int i=1;i<=n;i++)p[i]=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		edge[i].u=x;edge[i].v=y;edge[i].w=inf;
	}
	for(int i=1;i<=q;i++){
		int op=read(),x=read();
		if(op==1){
			a[++cnt].t=i;a[cnt].x=x;
		}else edge[x].w=i-1;
	}sort(edge+1,edge+m+1,cmp);kruskal();dep[tot]=1;dfs(tot);
	for(int i=1;i<=n;i++)update(1,1,n,dfn[i],p[i]);
	for(int i=1;i<=cnt;i++){
		int now=a[i].x;
		for(int j=19;j>=0;j--)
			if(val[jmp[now][j]]>=a[i].t)now=jmp[now][j];
		int ans=Query(1,1,n,L[now],R[now]);
		printf("%d\n",p[ans]);
		p[ans]=0;update(1,1,n,dfn[ans],p[ans]);
	}return 0;
}

#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;

struct IO
{
	#define MAXSIZE (1 << 20)
	#define isdigit(x) (x >= '0' && x <= '9')
  	char buf[MAXSIZE],*p1,*p2;
  	char pbuf[MAXSIZE],*pp;
  	IO():p1(buf),p2(buf),pp(pbuf){}
  	inline char gc() {
    	return getchar();
    	if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
    	return p1==p2?' ':*p1++;
  	}
	inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
  	template <class T>
  	inline void read(T &x)
	{
	    register double tmp=1;register bool sign=0; x=0;
	    register char ch=gc();
	    for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
	    for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
	    if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
	    if (sign) x=-x;
  	}
  	inline void read(char *s)
	{
    	register char ch=gc();
		for (;blank(ch);ch=gc());
		for (;!blank(ch);ch=gc()) *s++=ch;
    	*s=0;
  	}
  	inline void read(char &c) {for(c=gc();blank(c);c=gc());}
  	template<class t> inline void write(t x){
		if(x<0) putchar('-'),write(-x);
		else{if(x>9) write(x/10);putchar('0'+x%10);}
	}
} io;

const int mod=1e9+7;
const int mo=998244353;
const int N=2e5+5;

int n,m,T,a[N],col[N],qx[N],qy[N],fa[N],siz[N];
int ux[N],uy[N],del[N],ok[N];
vector<int> g[N];
pair<int,int> Q[N];

inline int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

inline int Query(int x)
{
//	cout<<"??"<<x<<endl;
//	For(i,0,(int)g[x].size()-1) cout<<g[x][i]<<" "<<col[g[x][i]]<<" "<<ok[g[x][i]]<<endl; puts("");
	while(g[x].size()&&(col[g[x].back()]!=x||ok[g[x].back()])) g[x].pop_back();
	if(g[x].empty()) return 0;
	int ans=g[x].back();
	g[x].pop_back(),ok[ans]=1;
	return ans;
}

int main()
{
	io.read(n),io.read(m),io.read(T);
	For(i,1,n) io.read(a[i]),g[i].pb(a[i]),fa[i]=i,siz[i]=1;
	For(i,1,m) io.read(ux[i]),io.read(uy[i]);
	For(i,1,T)
	{
		int opt,x;
		io.read(opt),io.read(x);
		Q[i]=make_pair(opt,x);
		if(opt==2) del[x]=1;
	}
	For(i,1,m) if(!del[i])
	{
		int fx=find(ux[i]),fy=find(uy[i]);
		if(fx==fy) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx];
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	Dow(i,T,1)
	{
		pair<int,int> u=Q[i];
		int op=u.first,x=u.second;
		int fx=find(ux[x]),fy=find(uy[x]);
		if(fx==fy||op==1) continue;
		if(siz[fx]>siz[fy]) swap(fx,fy);
		fa[fx]=fy,siz[fy]+=siz[fx],qx[i]=fx;
		For(j,0,(int)g[fx].size()-1) g[fy].pb(g[fx][j]);
	}
	For(i,1,n) sort(g[i].begin(),g[i].end());
	For(i,1,n) col[a[i]]=find(i);
	For(i,1,T)
	{
		pair<int,int> u=Q[i];
		int op=u.first,x=u.second;
		if(op==1) io.write(Query(find(x))),puts("");
		else if(qx[i])
		{
			For(j,0,g[qx[i]].size()-1) col[g[qx[i]][j]]=qx[i];
			fa[qx[i]]=qx[i];
		}
	}
	return 0;
}

#include <bits/stdc++.h>

using namespace std;

class segtree {
 public:
  struct node {
    int mx = -1;

    void apply(int l, int r, int v) {
      mx = v;
    }
  };

  node unite(const node &a, const node &b) const {
    node res;
    res.mx = max(a.mx, b.mx);
    return res;
  }

  inline void push(int x, int l, int r) {
  }

  inline void pull(int x, int z) {
    tree[x] = unite(tree[x + 1], tree[z]);
  }

  int n;
  vector<node> tree;

  void build(int x, int l, int r) {
    if (l == r) {
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    build(x + 1, l, y);
    build(z, y + 1, r);
    pull(x, z);
  }

  template <typename M>
  void build(int x, int l, int r, const vector<M> &v) {
    if (l == r) {
      tree[x].apply(l, r, v[l]);
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    build(x + 1, l, y, v);
    build(z, y + 1, r, v);
    pull(x, z);
  }

  node get(int x, int l, int r, int ll, int rr) {
    if (ll <= l && r <= rr) {
      return tree[x];
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    push(x, l, r);
    node res{};
    if (rr <= y) {
      res = get(x + 1, l, y, ll, rr);
    } else {
      if (ll > y) {
        res = get(z, y + 1, r, ll, rr);
      } else {
        res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr));
      }
    }
    pull(x, z);
    return res;
  }

  template <typename... M>
  void modify(int x, int l, int r, int ll, int rr, const M&... v) {
    if (ll <= l && r <= rr) {
      tree[x].apply(l, r, v...);
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    push(x, l, r);
    if (ll <= y) {
      modify(x + 1, l, y, ll, rr, v...);
    }
    if (rr > y) {
      modify(z, y + 1, r, ll, rr, v...);
    }
    pull(x, z);
  }

  int find_first_knowingly(int x, int l, int r, const function<bool(const node&)> &f) {
    if (l == r) {
      return l;
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res;
    if (f(tree[x + 1])) {
      res = find_first_knowingly(x + 1, l, y, f);
    } else {
      res = find_first_knowingly(z, y + 1, r, f);
    }
    pull(x, z);
    return res;
  }

  int find_first(int x, int l, int r, int ll, int rr, const function<bool(const node&)> &f) {
    if (ll <= l && r <= rr) {
      if (!f(tree[x])) {
        return -1;
      }
      return find_first_knowingly(x, l, r, f);
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res = -1;
    if (ll <= y) {
      res = find_first(x + 1, l, y, ll, rr, f);
    }
    if (rr > y && res == -1) {
      res = find_first(z, y + 1, r, ll, rr, f);
    }
    pull(x, z);
    return res;
  }

  int find_last_knowingly(int x, int l, int r, const function<bool(const node&)> &f) {
    if (l == r) {
      return l;
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res;
    if (f(tree[z])) {
      res = find_last_knowingly(z, y + 1, r, f);
    } else {
      res = find_last_knowingly(x + 1, l, y, f);
    }
    pull(x, z);
    return res;
  }

  int find_last(int x, int l, int r, int ll, int rr, const function<bool(const node&)> &f) {
    if (ll <= l && r <= rr) {
      if (!f(tree[x])) {
        return -1;
      }
      return find_last_knowingly(x, l, r, f);
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res = -1;
    if (rr > y) {
      res = find_last(z, y + 1, r, ll, rr, f);
    }
    if (ll <= y && res == -1) {
      res = find_last(x + 1, l, y, ll, rr, f);
    }
    pull(x, z);
    return res;
  }

  segtree(int _n) : n(_n) {
    assert(n > 0);
    tree.resize(2 * n - 1);
    build(0, 0, n - 1);
  }

  template <typename M>
  segtree(const vector<M> &v) {
    n = v.size();
    assert(n > 0);
    tree.resize(2 * n - 1);
    build(0, 0, n - 1, v);
  }

  node get(int ll, int rr) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return get(0, 0, n - 1, ll, rr);
  }

  node get(int p) {
    assert(0 <= p && p <= n - 1);
    return get(0, 0, n - 1, p, p);
  }

  template <typename... M>
  void modify(int ll, int rr, const M&... v) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    modify(0, 0, n - 1, ll, rr, v...);
  }

  // find_first and find_last call all FALSE elements
  // to the left (right) of the sought position exactly once

  int find_first(int ll, int rr, const function<bool(const node&)> &f) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return find_first(0, 0, n - 1, ll, rr, f);
  }

  int find_last(int ll, int rr, const function<bool(const node&)> &f) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return find_last(0, 0, n - 1, ll, rr, f);
  }
};

class dsu {
 public:
  vector<int> p;
  int n;

  dsu(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
  }

  inline int get(int x) {
    return (x == p[x] ? x : (p[x] = get(p[x])));
  }

  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) {
      p[x] = y;
      return true;
    }
    return false;
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  vector<int> p(n);
  vector<int> pos(n);
  for (int i = 0; i < n; i++) {
    cin >> p[i];
    --p[i];
    pos[p[i]] = i;
  }
  vector<int> from(m);
  vector<int> to(m);
  for (int i = 0; i < m; i++) {
    cin >> from[i] >> to[i];
    --from[i]; --to[i];
  }
  vector<int> op(q);
  vector<int> id(q);
  for (int i = 0; i < q; i++) {
    cin >> op[i] >> id[i];
    --id[i];
  }
  vector<bool> removed(m, false);
  for (int i = 0; i < q; i++) {
    if (op[i] == 2) {
      removed[id[i]] = true;
    }
  }
  dsu d(n);
  vector<int> head(n);
  vector<int> tail(n);
  iota(head.begin(), head.end(), 0);
  iota(tail.begin(), tail.end(), 0);
  vector<int> nxt(n, -1);
  for (int i = 0; i < m; i++) {
    if (!removed[i]) {
      int x = d.get(from[i]);
      int y = d.get(to[i]);
      if (x != y) {
        d.unite(x, y);
        nxt[tail[x]] = head[y];
        head[y] = head[x];
      }
    }
  }
  vector<int> start(q, -1);
  vector<int> finish(q, -1);
  for (int i = q - 1; i >= 0; i--) {
    if (op[i] == 2) {
      int x = d.get(from[id[i]]);
      int y = d.get(to[id[i]]);
      if (x != y) {
        d.unite(x, y);
        nxt[tail[x]] = head[y];
        head[y] = head[x];
      }
    } else {
      int x = d.get(id[i]);
      start[i] = head[x];
      finish[i] = tail[x];
    }
  }
  vector<int> seq;
  for (int i = 0; i < n; i++) {
    if (d.get(i) == i) {
      int u = head[i];
      while (true) {
        seq.push_back(u);
        if (u == tail[i]) {
          break;
        }
        u = nxt[u];
      }
    }
  }
  assert((int) seq.size() == n);
  vector<int> in_seq(n, -1);
  for (int i = 0; i < n; i++) {
    in_seq[seq[i]] = i;
  }
  vector<int> arr(n);
  for (int i = 0; i < n; i++) {
    arr[i] = p[seq[i]];
  }
  segtree st(arr);
  for (int i = 0; i < q; i++) {
    if (op[i] == 1) {
      int L = in_seq[start[i]];
      int R = in_seq[finish[i]];
      int res = st.get(L, R).mx;
      cout << res + 1 << '\n';
      if (res != -1) {
        st.modify(pos[res], pos[res], -1);
      }
    }
  }
  return 0;
}

#include <bits/stdc++.h>
#include <random>

using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
//#define int ll
typedef vector<char> vc;
typedef vector<vc> vvc;
typedef vector<vvc> vvvc;
typedef pair<int, int> pii;
typedef pair<pii, pii> piii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector< vi > vvi;
typedef vector< vvi > vvvi;
typedef vector<short> vs;
typedef vector<vs> vvs;
typedef vector<vvs> vvvs;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<vvl> vvvl;
typedef vector<ld> vld;
typedef vector<vld> vvld;
typedef vector<vvld> vvvld;
typedef vector<string> vst;
typedef vector<vst> vvst;
typedef pair<ld, ld> pld;

#define inmin(a, b) a = min(a, (b))
#define inmax(a, b) a = max(a, (b))
#define ALL(a) a.begin(),a.end()
#define RALL(a) a.rbegin(),a.rend()
#define sqr(x) ((x) * (x))
#define fori(i, n) for(int i = 0; i < int(n); ++i)
#define SZ(a) ((int)((a).size()))
#define triple(T) tuple<T, T, T>
#define quad(T) tuple<T, T, T, T>
#define watch(x) cerr << (#x) << " = " << (x) << endl;

#ifdef RUS_HOME
#define cerr cout
#else
#define cerr if (false) cerr
#endif

const double PI = 2 * acos(0.0);
#define rand shittttty_shit
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
mt19937_64 rng_64(chrono::steady_clock::now().time_since_epoch().count());

const string DIGITS = "0123456789";
const string ALPH = "abcdefghijklmnopqrstuvwxyz";

template <class T0, class T1>
inline ostream & operator << (ostream &out, pair<T0, T1> &a) {
    return out << "{" << a.first << ", " << a.second << "}";
}

template <class T0, class T1>
inline istream & operator >> (istream &in, pair<T0, T1> &a) {
    return in >> a.first >> a.second;
}

template <class T0, class T1, class T2>
inline ostream & operator << (ostream &out, tuple<T0, T1, T2> &a) {
    return out << "{" << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << "}";
}

template <class T0, class T1, class T2, class T3>
inline ostream & operator << (ostream &out, tuple<T0, T1, T2, T3> &a) {
    return out << "{" << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << ", " <<  get<3>(a) << "}";
}

template<class T>
inline ostream & operator << (ostream &out, vector<T> &a) {
    out << "[";
    fori (i, a.size())
        out << a[i] << vector<string>{", ", "]  "}[i + 1 == a.size()];
    return out;
}

void smain();

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
#ifdef RUS_HOME
    freopen("input", "r", stdin);
    //freopen("output.txt", "w", stdout);
    clock_t start = clock();
#else
    //("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    cout << setprecision(12) << fixed;
    smain();
#ifdef RUS_HOME
    cout << "\n\n\n\nTOTAL EXECUTION TIME: " << float( clock () - start ) /  CLOCKS_PER_SEC << endl;
#endif
    return 0;
}

const int MOD=1e9+7,N=2e5+100,oo=1e18+10,A=26,M=3e5+100,K=5e5+100;

set<int>g[N];
int p[N];
pii edges[M];
pii q[K];
int ans[K],lst[K];

int par[N],sz[N];
vi f[N];
vi kek[N];
map<int,int>st[N];
bool used[N];

int merge(int v,int u){
    v=par[v];
    u=par[u];
    if(v==u)
        return 0;
    int fl=0;
    if(sz[v]<sz[u]){
        swap(v,u);
        fl=1;
    }
    for(int i=0;i<SZ(f[u]);i++){
        int y=f[u][i];
        par[y]=v;
        kek[y].push_back(v);
        f[v].push_back(y);
        st[v][p[y]]=y;
    }
    sz[v]+=sz[u];
    return fl;
}

void antimerge(int v,int u){
    if(v==u)
        return;
    for(int i=0;i<SZ(f[u]);i++){
        int y=f[u][i];
        par[y]=u;
        if(!used[y])
            st[v].erase(p[y]);
    }
}

void rec(int nm){
    if(!nm)
        return;
    int ed=q[nm].second;
    int u=par[edges[ed].first],v=par[edges[ed].second];
    int fl=merge(u,v);
    if(fl)
        swap(u,v);
    int h=lst[nm];
    rec(h);
    for(int i=h+1;i<nm;i++){
        int a=par[q[i].second];
        while(SZ(st[a])){
            auto it=st[a].end(); it--;
            if(used[(*it).second])
                st[a].erase(it);
            else{
                int y=(*it).second;
                ans[i]=p[y];
                used[y]=true;
                break;
            }
        }
    }
    antimerge(u,v);
}

void smain() {

    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        cin>>p[i];
    }
    for(int i=1;i<=m;i++){
        int a,b;
        cin>>a>>b;
        g[a].insert(b);
        g[b].insert(a);
        edges[i]={a,b};
    }

    for(int i=1;i<=k;i++){
        int a,b;
        cin>>a>>b;
        q[i]={a,b};
        if(a==2){
            int u=edges[b].first,v=edges[b].second;
            g[u].erase(v);
            g[v].erase(u);
        }
    }

    for(int i=1;i<=n;i++){
        par[i]=i;
        sz[i]=1;
        f[i]={i};
        kek[i]={i};
        st[i][p[i]]=i;
    }

    for(int i=1;i<=n;i++){
        for(auto u:g[i]){
            merge(i,u);
        }
    }
    edges[m+1]={1,1};
    q[k+1]={2,m+1};
    q[0]={2,m+1};
    for(int i=1;i<=k;i++){
        if(q[i-1].first==2)
            lst[i]=i-1;
        else
            lst[i]=lst[i-1];
    }
    rec(k+1);

    for(int i=1;i<=k;i++){
        if(q[i].first==1){
            cout<<ans[i]<<"\n";
        }
    }

}

/**
 *    author:  tourist
 *    created: 09.05.1945 00:43:00
**/
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define fi first
#define se second
#define pb emplace_back
#define all(x) x.begin(),x.end()
#define re return
#define mp make_pair
#define sz(x) ((int)(x).size())
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rrep(i, n) for (int i = (n) - 1; i >= 0; i--)
#define unq(x) (x.resize(unique(all(x)) - x.begin()))
#define sqr(x) ((x)*(x))
#define int long long

using namespace std;
using namespace __gnu_pbds;

typedef tree <int, null_type, less <int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;

typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int, int> ii;
typedef vector<ii> vii;
typedef vector<string> vs;
typedef pair<ll, ll> pll;
typedef vector<ll> vll;
typedef pair<double, double> pdd;
typedef double D;

double getTime() { return clock() / (double) CLOCKS_PER_SEC;};

const int mod = 1e9 + 7;
const ll INF = 3e18;
const int N = 2e5 + 5;
const int P0 = 437;
const int P1 = 343;
const int d = 400;

vi start(N), was(N), pa(N), Sz(N);
vii v[N];
int timer = 1;
set <int> group[N];
vi st_g[N];

void Make(int i)
{
    pa[i] = i;
    Sz[i] = 1;
}

int Find (int pos)
{
    if(pa[pos] != pos)
        pa[pos] = Find(pa[pos]);
    re pa[pos];
}

vi from, to;
vvi g;

vi lol;

void Union(int i, int j)
{
    int i_ind = Find(i), j_ind = Find(j);
    if(i_ind == j_ind)
    {
        from.pb(-1);
        to.pb(-1);
        g.pb(lol);
        re;
    }
    if(Sz[i_ind] <= Sz[j_ind])
    {
        pa[i_ind] = j_ind;
        Sz[j_ind] += Sz[i_ind];
        from.pb(j_ind);
        to.pb(i_ind);
        g.pb(st_g[i_ind]);
        for (int x : st_g[i_ind])
            st_g[j_ind].pb(x);
    }
    else
    {
        pa[j_ind] = i_ind;
        Sz[i_ind] += Sz[j_ind];
        from.pb(i_ind);
        to.pb(j_ind);
        g.pb(st_g[j_ind]);
        for (int x : st_g[j_ind])
            st_g[i_ind].pb(x);
    }
}

void dfs (int pos)
{
    was[pos] = timer;
    Sz[timer]++;
    for (auto u : v[pos])
    {
        int x = u.fi, i = u.se;
        if(!was[x] && start[i])
            dfs(x);
    }
}

void solve()
{
    int n, m, k;
    cin >> n >> m >> k;
    vi p(n);
    rep(i, n)
        cin >> p[i];
    vi L(m), R(m);
    start.resize(n);
    rep(i, m)
    {
        start[i] = 1;
        int l, r;
        cin >> l >> r;
        l--; r--;
        L[i] = l; R[i] = r;
        v[l].pb(r, i);
        v[r].pb(l, i);
    }
    vi t(k), a(k);
    rep(i, k)
    {
        cin >> t[i] >> a[i];
        a[i]--;
        if(t[i] == 2)
            start[a[i]] = 0;
    }
    rep(i, n)
    {
        if(!was[i])
        {
            dfs(i);
            timer++;
        }
//        cout << was[i] << ' ';
    }
//    cout << '\n';
    vi Was(n + 1, -1);
    rep(i, n)
    {
        if(Was[was[i]] == -1)
        {
            Was[was[i]] = i;
            Make(i);
            st_g[i].pb(i);
        }
        else
        {
            Make(i);
            st_g[i].pb(i);
            Union(Was[was[i]], i);
        }
    }

    from.clear();
    to.clear();
    g.clear();

    rrep(i, k)
    {
        if(t[i] == 1)
            continue;
        Union(L[a[i]], R[a[i]]);
    }

    reverse(all(from));
    reverse(all(to));
    reverse(all(g));

    vi now(n);

    rep(i, n)
    {
        int ind = Find(i);
        group[ind].insert(p[i]);
        now[i] = ind;
//        cout << now[i] << ' ';
    }

    int pos = 0;

    rep(i, k)
    {
        if(t[i] == 1)
        {
            auto it = group[now[a[i]]].end();
            it--;
            cout << *it << '\n';
            group[now[a[i]]].erase(it);
            group[now[a[i]]].insert(0);
        }
        else
        {
            if(from[pos] != -1)
                for (int x : g[pos])
                {
                    group[from[pos]].erase(p[x]);
                    group[to[pos]].insert(p[x]);
                    now[x] = to[pos];
                }
            pos++;
        }
    }
    re;

}

signed main()
{
    //freopen("input.txt ", "r", stdin);
    //freopen("output.txt", "w", stdout);
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int qq = 1;
//    cin >> qq;
    while(qq--)
        solve();
}

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
const int N = 5e5 + 3;
const int M = 3e5 + 4;
const int QU = 5e5 + 3;
typedef pair < int, int > ii;
int n, m, q;
int val[N];
ii edge[M];
ii qu[QU];
bool kt[M];
int cha[N], rnk[N];
int init;
int tin[N], tout[N];
vector < int > adj[N];

int findcha(int u)
{
    if (cha[u] != u) return cha[u] = findcha(cha[u]);

    return cha[u];
}

bool join(int u, int v)
{
    u = findcha(u);
    v = findcha(v);

    if (u == v) return false;

    n++;
    cha[u] = n;
    cha[v] = n;
    cha[n] = n;
    adj[n].push_back(u);
    adj[n].push_back(v);

    return true;
}

int dem = 0;

void dfs(int i, int j)
{
    dem++;
    tin[i] = dem;

    for (int u : adj[i])
    {
        if (u == j) continue;

        dfs(u, i);
    }

    tout[i] = dem;
}

struct ok
{
    int lo;
    int hi;
    int val;
    int pos;
};
ok Node[4 * N];

void build(int id, int l, int r)
{
    Node[id].lo = l; Node[id].hi = r;

    if (l == r) return;

    int mid = (l + r) / 2;

    build(id * 2, l, mid);
    build(id * 2 + 1, mid + 1, r);
}

void update(int id, int pos, int val)
{
    if (Node[id].lo > pos || Node[id].hi < pos) return;

    if (Node[id].lo == Node[id].hi)
    {
        Node[id].val = val;
        Node[id].pos = pos;

        return;
    }

    update(id * 2, pos, val);
    update(id * 2 + 1, pos, val);

    Node[id].val = max(Node[id * 2].val, Node[id * 2 + 1].val);

    if (Node[id * 2].val > Node[id * 2 + 1].val)
        Node[id].pos = Node[id * 2].pos;
    else
        Node[id].pos = Node[id * 2 + 1].pos;
}

ii getma(int id, int l, int r)
{
    if (Node[id].lo > r || Node[id].hi < l) return {0, 0};

    if (l <= Node[id].lo && Node[id].hi <= r)
        return {Node[id].val, Node[id].pos};

    return max(getma(id * 2, l, r), getma(id * 2 + 1, l, r));
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    //freopen("t.inp","r",stdin); freopen("t.out","w",stdout);

    cin >> n >> m >> q;

    for (int i = 1; i <= n; i++)
        cin >> val[i];

    memset(kt, true, sizeof kt);

    for (int i = 1; i <= m; i++)
        cin >> edge[i].fi >> edge[i].se;

    for (int i = 1; i <= q; i++)
    {
        cin >> qu[i].first >> qu[i].second;

        if (qu[i].first == 2) kt[qu[i].second] = false;
    }

    for (int i = 1; i <= n; i++)
        cha[i] = i;

    init = n;

    for (int i = 1; i <= m; i++)
    {
        if (!kt[i]) continue;

        join(edge[i].fi, edge[i].se);
    }

    for (int i = q; i > 0; i--)
    {
        if (qu[i].first == 2)
        {
            int id = qu[i].second;

            join(edge[id].fi, edge[id].se);
        }
        else
        {
            qu[i].second = findcha(qu[i].second);
        }
    }

    dfs(n, 0);

    build(1, 1, dem);

    for (int i = 1; i <= init; i++)
        update(1, tin[i], val[i]);

    for (int i = 1; i <= q; i++)
    {
        if (qu[i].first == 1)
        {
            ii top = getma(1, tin[qu[i].second], tout[qu[i].second]);

            cout << top.first << '\n';

            update(1, top.second, 0);
        }
    }
}

/**
 ____ ____ ____ ____ ____
||a |||t |||o |||d |||o ||
||__|||__|||__|||__|||__||
|/__\|/__\|/__\|/__\|/__\|

**/

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N_MAX = 200002;
const int M_MAX = 300002;
const int Q_MAX = 500002;

int n, m, q;

int p[N_MAX];

struct Edge
{
    int u, v;
};

Edge edges[M_MAX];

struct Query
{
    int type;
    int x;
};

Query queries[Q_MAX];

int aux[Q_MAX];

int root[N_MAX + Q_MAX];

int leftSon[N_MAX + Q_MAX], rightSon[N_MAX + Q_MAX];

int findRoot (int u)
{
    if(root[u] == u)
        return u;
    return root[u] = findRoot(root[u]);
}

int cntNodes;

void join (int u, int v)
{
    u = findRoot(u);
    v = findRoot(v);
    if(u == v)
        return;
    cntNodes++;
    leftSon[cntNodes] = u;
    rightSon[cntNodes] = v;
    root[u] = root[v] = cntNodes;
    root[cntNodes] = cntNodes;
}

int L[N_MAX + Q_MAX], R[N_MAX + Q_MAX];

int label[N_MAX + Q_MAX];
int inv[N_MAX + Q_MAX];

int curr;

void dfs (int u)
{
    inv[++curr] = u;
    label[u] = curr;
    L[u] = R[u] = label[u];
    if(leftSon[u] != 0)
    {
        dfs(leftSon[u]);
        L[u] = L[leftSon[u]];
    }
    if(rightSon[u] != 0)
    {
        dfs(rightSon[u]);
        R[u] = R[rightSon[u]];
    }
}

int SGT[(N_MAX + Q_MAX) * 4];

int SGTjoin (int a, int b)
{
    if(p[inv[a]] > p[inv[b]])
        return a;
    else
        return b;
}

void SGTbuild (int node, int l, int r)
{
    if(l == r)
    {
        SGT[node] = l;
        return;
    }
    int mid = ((l + r) >> 1), lSon = (node << 1), rSon = (lSon | 1);
    SGTbuild(lSon, l, mid);
    SGTbuild(rSon, mid + 1, r);
    SGT[node] = SGTjoin(SGT[lSon], SGT[rSon]);
}

void SGTupdate (int node, int l, int r, int upos)
{
    if(l == r)
    {
        p[inv[l]] = 0;
        return;
    }
    int mid = ((l + r) >> 1), lSon = (node << 1), rSon = (lSon | 1);
    if(upos <= mid)
        SGTupdate(lSon, l, mid, upos);
    else
        SGTupdate(rSon, mid + 1, r, upos);
    SGT[node] = SGTjoin(SGT[lSon], SGT[rSon]);
}

int SGTquery (int node, int l, int r, int ql, int qr)
{
    if(ql <= l && r <= qr)
        return SGT[node];
    int mid = ((l + r) >> 1), lSon = (node << 1), rSon = (lSon | 1);
    if(ql <= mid && mid + 1 <= qr)
        return SGTjoin(SGTquery(lSon, l, mid, ql, qr), SGTquery(rSon, mid + 1, r, ql, qr));
    else if(ql <= mid)
        return SGTquery(lSon, l, mid, ql, qr);
    else
        return SGTquery(rSon, mid + 1, r, ql, qr);
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i++)
        cin >> p[i];
    for(int i = 1; i <= m; i++)
        cin >> edges[i].u >> edges[i].v;
    for(int i = 1; i <= q; i++)
        cin >> queries[i].type >> queries[i].x;
    for(int i = 1; i <= n; i++)
        root[i] = i;
    cntNodes = n;
    for(int i = q; i >= 1; i--)
        if(queries[i].type == 1)
            aux[i] = findRoot(queries[i].x);
        else
            join(edges[queries[i].x].u, edges[queries[i].x].v);
    cout << "*\n";
    dfs(root[1]);
    SGTbuild(1, 1, cntNodes);
    for(int i = 1; i <= q; i++)
        if(queries[i].type == 1)
        {
            int pos = SGTquery(1, 1, cntNodes, L[aux[i]], R[aux[i]]);
            cout << p[inv[pos]] << "\n";
            SGTupdate(1, 1, cntNodes, pos);
        }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;
#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifndef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
	*this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
typedef pair<long long, int> pli;
typedef long long ll;
#define f first
#define s second
#define endl '\n'
#define all(x) x.begin(),x.end()
const int N=5e5+1;
int p[ N ],tin [ N ],tout[ N ],timer=0;
int get( int v ){
    return p[v] = ( v == p[v] ? v : get( p[ v ] ) );
}
int n,m,q;
vector<int> g [ N ];
pii t[ 4 * N ];
int a[ N ];
int obr[N];
void mg(int a, int b){
    int c = get( a ), d = get( b );
    n++;
    p[c]=n;
    p[d]=n;
    g[ n ].emplace_back(c);
    g[ n ].emplace_back(d);
    return ;
}
void dfs(int v, int p){
    tin[ v ] = ++timer;
    obr[ timer ] = v;
    for(auto &z : g[ v ]){
        dfs( z, v );
    }
    tout[ v ] = timer;
}
void b_tr(int v,int tl,int tr){
    if(tl == tr){
        t[v]={a[obr[tl]],tl};
    }
    else{
        int tm=(tl+tr)>>1;
        b_tr(2*v,tl,tm);
        b_tr(2*v+1,tm+1,tr);
        t[v]=max(t[2*v],t[2*v+1]);
    }
}
pii getMax(int l,int r,int v,int tl,int tr){
    if(tl>=l && tr<=r){
        return t[v];
    }
    if(tl>r || tr<l) return {0,n};
    int tm=(tl+tr)>>1;
    return max(getMax(l,r,2*v,tl,tm),getMax(l,r,2*v+1,tm+1,tr));
}
void upd(int id,int v,int tl,int tr){
    if(tl==tr){
        t[v].first=0;
        return ;
    }
    int tm=(tl+tr)>>1;
    if(tm>=id)
        upd(id,2*v,tl,tm);
    else
        upd(id,2*v+1,tm+1,tr);
    t[v]=max(t[2*v],t[2*v+1]);
}
pii e[N];
bool ex[N];
pii qe[N];
signed main(){
    cin.tie(0);cout.tie(0);ios_base::sync_with_stdio(false);
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i = 0;i < m;i++){
        int v,u;
        cin>>v>>u;
        e[i]={v,u};
    }
    iota(p,p+N,0);
    for(int i = 0;i < q;i++){
        int tp;
        cin>>tp;
        int id;
        cin>>id;
        if(tp==2){
            ex[id-1]=1;
        }
        qe[i]={tp,id};
    }
    for(int i = 0; i < m;i++){
        if(!ex[i]){
            mg(e[i].f,e[i].s);
        }
    }
    for(int i = q - 1; ~ i; --i){
        if(qe[i].f==2)
            mg(e[qe[i].s-1].f,e[qe[i].s-1].s);
        else {
            qe[i].s=get(qe[i].s);
        }
    }
    for(int i = 1;i <= n; i++){
        if(get(i)==i)
            dfs(i,i);
    }
    b_tr(1,1,n);
    for(int i = 0; i<q; i++){
        if(qe[i].f==1){
            int id=qe[i].s;
            auto w=getMax(tin[id],tout[id],1,1,n);
            upd(w.s,1,1,n);
            cout<<w.f<<endl;
        }
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
    if(ql <= mid) ret = chkmax(ret, ask(x<<1, l, mid, ql, qr));
    if(qr > mid) ret = chkmax(ret, ask(x<<1|1, mid+1, r, ql, qr));
    return ret;
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = t, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    assert(w[x] >= w[ac[x][0]]);
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][0] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    for(int i = L-1; ~i; --i) if(ac[x][i]&&w[ac[x][i]] > t) x = ac[x][i];
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n), assert(tk == n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  assert(k), del(1, 1, n, pos[k]);
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
    if(ql <= mid) ret = chkmax(ret, ask(x<<1, l, mid, ql, qr));
    if(qr > mid) ret = chkmax(ret, ask(x<<1|1, mid+1, r, ql, qr));
    return ret;
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = t, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    assert(w[x] >= w[ac[x][0]]);
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][0] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    // for(int i = L-1; ~i; --i) if(w[ac[x][i]] > t) x = ac[x][i];
    for( ; ac[x][0]&&ac[x][0] > t; x = ac[x][0]);
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n), assert(tk == n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  assert(k), del(1, 1, n, pos[k]);
    }
    return 0;
}

#define _USE_MATH_DEFINES
//#pragma GCC optimize("O3")
// #pragma GCC target("sse4")

#include <bits/stdc++.h>
using namespace std;

#define LSB(i) ((i) & -(i)) // zeroes all the bits except the least significant one

#define OPEN(a) freopen(a, "r", stdin)
#define F first
#define S second
#define PB push_back
#define BOOST ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ALL(i) begin((i)), end((i))
#define SZ(i) ((int)i.size())
#define SORT(a) sort(ALL(a))

using LL = long long;
using LD = long double;//__float128;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
using PLD = pair<LD, LD>;
using VI = vector<int>;
using VLL = vector<LL>;
using VLD = vector<LD>;
using VPII = vector<PII>;
using VPLL = vector<PLL>;
using VPLD = vector<PLD>;
using VVI = vector<VI>;

#define GET_MACRO(_1, _2, _3, _4, NAME, ...) NAME
#define __FOR3(i, a, n, inc) for(int i = (a); (inc) > 0 ? i < (n) : i >= (n); i += (inc))
#define __FOR2(i, a, n) __FOR3(i, a, n, 1)
#define __FOR1(i, n) __FOR2(i, 0, n)
#define FOR(...) GET_MACRO(__VA_ARGS__, __FOR3, __FOR2, __FOR1)(__VA_ARGS__)

#define REV(a,b) for(int a= b; a >= 0; --a)
#define FRU(a,b) for(const auto& a: b)
#define FRUM(a,b) for(auto& a : b)

const int inf = 1e9 + 7;
const int MOD = 998244353;
const LL INF = 1e18 + 7;
const long double PI = acos(-1);
const LD EPS = 1e-9;

namespace input {
    template< class T> istream& operator>>(istream& st, vector<T> & container) { for (auto& u : container) st >> u; return st; }
    template< class T, size_t N> istream& operator>>(istream& st, array<T, N> & container) { for (auto& u : container) st >> u; return st; }
    template <class T, class U> istream& operator>>(istream& st, pair<T, U> & p) { st >> p.first >> p.second; return st; }

    void re() {}
    template<typename T, typename... TArgs> void re(T& x, TArgs&... rest) { cin >> x; re(rest...); }
}
using namespace input;

namespace output
{
    template< class T> ostream& operator<<(ostream& st, const vector<T> & container) { for (auto& u : container) st << u << ' '; return st; }
    template< class T, size_t N> ostream& operator<<(ostream& st, const array<T, N> & container) { for (auto& u : container) st << u << ' '; return st; }
    template <class T, class U> ostream& operator<<(ostream& st, pair<T, U> p) { st << p.first << ' ' << p.second; return st; }

    void pr() {}
    template <typename T> void pr(const T& x) { cout << x; }
    template <typename T, typename... TArgs> void pr(const T& x, const TArgs&... rest) { cout << x << ' '; pr(rest...); }
    template <typename... TArgs> void prln(const TArgs&... args) { pr(args...); cout << '\n'; }
}
using namespace output;

namespace pairs
{
    template<class T, class U, class V> pair<T, U> operator* (pair<T, U>p, V val) { return{ p.first * val, p.second * val }; }
    template<class T, class U, class V> pair<T, U> operator/ (pair<T, U>p, V val) { return{ p.first / val, p.second / val }; }
    template<class T, class U>  pair<T, U> operator- (pair<T, U> a, pair<T, U> b) { return{ a.first - b.first, a.second - b.second }; }
    template<class T, class U>  pair<T, U> operator+ (pair<T, U> a, pair<T, U> b) { return{ a.first + b.first, a.second + b.second }; }
}
using namespace pairs;

namespace triples
{
#define TT1T2T3 template<class T1, class T2, class T3>
#define TT1T2T3T4 template<class T1, class T2, class T3, class T4>
#define TRT1T2T3  triple<T1, T2, T3>
    TT1T2T3 struct triple { T1 x; T2 y; T3 z; triple() : x(T1()), y(T2()), z(T3()) {};
     triple(T1 _x, T2 _y, T3 _z) :x(_x), y(_y), z(_z) {} };
    TT1T2T3 bool operator<(const TRT1T2T3&t1, const TRT1T2T3&t2) { if (t1.x != t2.x)return t1.x < t2.x; if (t1.y != t2.y) return t1.y < t2.y; else return t1.z < t2.z; }
    TT1T2T3 bool operator>(const TRT1T2T3&t1, const TRT1T2T3&t2) { if (t1.x != t2.x)return t1.x > t2.x; if (t1.y != t2.y) return t1.y > t2.y; else return t1.z > t2.z; }
    TT1T2T3 bool operator==(const TRT1T2T3&t1, const TRT1T2T3&t2) { return (t1.x == t2.x && t1.y == t2.y && t1.z == t2.z); }
    TT1T2T3 inline istream& operator >> (istream& os, triple<T1, T2, T3>& t) { return os >> t.x >> t.y >> t.y; }
    TT1T2T3 ostream& operator << (ostream& os, const triple<T1, T2, T3>& t) { return os << t.x << " " << t.y << " " << t.z; }

    TT1T2T3 TRT1T2T3 operator+(TRT1T2T3 a, TRT1T2T3 b) { return { a.x + b.x, a.y + b.y, a.z + b.z }; }
    TT1T2T3 TRT1T2T3 operator-(TRT1T2T3 a, TRT1T2T3 b) { return { a.x - b.x, a.y - b.y, a.z - b.z }; }
    TT1T2T3T4 TRT1T2T3 operator*(TRT1T2T3 a, T4 val) { return { a.x * val, a.y * val, a.z * val }; }
    TT1T2T3T4 TRT1T2T3 operator/(TRT1T2T3 a, T4 val) { return { a.x / val, a.y / val, a.z / val }; }

#undef TT1T2T3T4
#undef TRT1T2T3
#undef TT1T2T3
    using TRII = triple<int, int, int>;
    using TRLL = triple<LL, LL, LL>;
    using TRLD = triple<LD, LD, LD>;
    using VTRII = vector<TRII>;
    using VTRLL = vector<TRLL>;
    using VTRLD = vector<TRLD>;
}
using namespace triples;

namespace geo
{
    template<class T> T dotProduct(pair<T, T> a, pair<T, T> b) { return a.first*b.first + a.second* b.second; }
    template<class T> T crossProduct(pair<T, T>a, pair<T, T> b) { return a.first * b.second - a.second * b.first; }
    template<class T> T lengthPow(pair<T, T> a) { return a.first*1ll*a.first + a.second*1ll*a.second; }
    template<class T> LD length(pair<T, T> a) { return sqrt(lengthPow(a)); }

    template<class T> T dotProduct(triple<T, T, T> a, triple<T, T, T> b) { return a.x*b.x + a.y* b.y + a.z*b.z; }
    template<class T> T crossProduct(triple<T, T, T> a, triple<T, T, T> b) { return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x }; }
    template<class T> T lengthPow(triple<T, T, T> a) { return a.x*1ll*a.x + a.y*1ll*a.y + a.z*1ll*a.z; }
    template<class T> LD length(triple<T, T, T> a) { return sqrt(lengthPow(a)); }
}
using namespace geo;

template <class T> T invGeneral(T a, T b) { // 0 < a < b, gcd(a,b) = 1
    a %= b;
    if (a == 0) return b == 1 ? 0 : -1;
    T x = invGeneral(b, a);
    return x == -1 ? -1 : ((1 - (LL)b * x) / a + b) % b;
}

template<class T> struct modular {
    T val;
    explicit operator T() const { return val; }
    modular() { val = 0; }
    modular(const LL& v) {
        val = (-MOD <= v && v <= MOD) ? v : v % MOD;
        if (val < 0) val += MOD;
    }

    friend ostream& operator<<(ostream& os, const modular& a) { return os << a.val; }
    friend void pr(const modular& a) { pr(a.val); }
    friend void re(modular& a) { LL x; re(x); a = modular(x); }

    friend bool operator==(const modular& a, const modular& b) { return a.val == b.val; }
    friend bool operator!=(const modular& a, const modular& b) { return !(a == b); }
    friend bool operator<(const modular& a, const modular& b) { return a.val < b.val; }

    modular operator-() const { return modular(-val); }
    modular& operator+=(const modular& m) { if ((val += m.val) >= MOD) val -= MOD; return *this; }
    modular& operator-=(const modular& m) { if ((val -= m.val) < 0) val += MOD; return *this; }
    modular& operator*=(const modular& m) { val = (LL)val*m.val%MOD; return *this; }
    friend modular pow(modular a, LL p) {
        modular ans = 1; for (; p; p /= 2, a *= a) if (p & 1) ans *= a;
        return ans;
    }
    friend modular inv(const modular& a) {
        auto i = invGeneral(a.val, MOD); assert(i != -1);
        return i;
    } // equivalent to return exp(b,MOD-2) if MOD is prime
    modular& operator/=(const modular& m) { return (*this) *= inv(m); }

    friend modular operator+(modular a, const modular& b) { return a += b; }
    friend modular operator-(modular a, const modular& b) { return a -= b; }
    friend modular operator*(modular a, const modular& b) { return a *= b; }
    friend modular operator/(modular a, const modular& b) { return a /= b; }
};

using MI = modular<int>;
using PMI = pair<MI, MI>;
using VMI = vector<MI>;
using VPMI = vector<PMI>;

namespace debug {
    template < typename _T > inline void _debug(const char *s, _T x) { cerr << s << " = " << x << "\n"; }
    template < typename _T, typename... args > void _debug(const char *s, _T x, args... a) { while (*s != ',') cerr << *s++; cerr << " = " << x << ','; _debug(s + 1, a...); }

#if 1 && defined(LOCAL)
#define debug(...) _debug(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...) 1999
#define cerr if(0) cout
#endif
}
using namespace debug;

template <class T> bool setMax(T& v, T newV) { if (v < newV) { v = newV; return true; } return false; }
template <class T> bool setMin(T& v, T newV) { if (v > newV) { v = newV; return true; } return false; }

const int N = 2e5 + 7;

namespace DSU
{
    int tab[N];
    int sz[N];
    VI members[N];
    void init(int n)
    {
        FOR(i, n)
        {
            sz[i] = 1;
            tab[i] = i;
            members[i] = {i};
        }
    }
    int Find(int a)
    {
        if(tab[a] != a)
            tab[a] = Find(tab[a]);
        return tab[a];
    }
    void Union(int a, int b)
    {
        a = Find(a);
        b = Find(b);

        if(a == b)
            return;
        if(sz[a] < sz[b])
            swap(a, b);

        tab[b] = a;
        sz[a] += sz[b];
        members[a].insert(members[a].end(), ALL( members[b]));
    }
}

int val[N];
bool validEdge[N];
bool ok[N];
VI ids[N];
PII queries[N];
int setID[N];

set<int, greater<int>> sety[2 * N];

void solve()
{
    int n, m, q;
    re(n, m, q);

    VPII kra;
    VI edgeQue;

    DSU::init(n);
    FOR(i, n)
    {
        validEdge[i] = true;
        re(val[i]);
    }

    FOR(i, m)
    {
        int a, b;
        re(a, b);
        --a, --b;
        kra.push_back({a, b});
    }
    FOR(i, q)
    {
        int t, a;
        re(t, a);
        --a;
        queries[i] = {t, a};
        if(t == 2) {
            validEdge[a] = false;
            edgeQue.push_back(a);
        }
    }
    reverse(ALL(edgeQue));
    FOR(i, m)
    {
        if(not validEdge[i])
            continue;
        DSU::Union(kra[i].first, kra[i].second);
    }

    FRU(edgeID, edgeQue)
    {
        auto a = DSU::Find(kra[edgeID].first);
        auto b = DSU::Find(kra[edgeID].second);

        if(a == b)
            continue;
        if(DSU::sz[a] > DSU::sz[b])
            swap(a, b);

        ids[edgeID] = DSU::members[a];
        DSU::Union(a, b);
    }

    int cnt = 0;
    map<int,int> iddd;
    FOR(i, n)
    {
        int a = DSU::Find(i);
        if(iddd.count(a) == 0)
            iddd[a] = ++cnt;
        setID[i] = iddd[a];
        sety[setID[i]].insert(val[i]);
    }

    FOR(i, q)
    {
        auto [t, a] = queries[i];
        if(t == 1)
        {
            auto & set = sety[setID[a]];
            if(set.empty())
            {
                prln(0);
                continue;
            }
            prln(*set.begin());
            set.erase(set.begin());
        }
        else
        {
            ++cnt;
            auto & setOld = sety[setID[kra[a].first]];
            auto & setNew = sety[cnt];

            for(auto u : ids[a])
            {
                setID[u] = cnt;
                if(setOld.erase(val[u]))
                    setNew.insert(val[u]);
            }
        }
    }

}

int main()
{
    // #ifndef LOCAL
        // freopen("input.txt", "r", stdin);
        // freopen("output.txt", "w", stdout);
    // #endif

    BOOST;
    cout << fixed << setprecision(13);
    int t = 1;
    // cerr << "testy!!!!\n"; cin >> t;
    for(int i = 1; i <= t; ++i)
    // string s;
    // while(cin >> s)
    {
        solve();
    }
    return 0;
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+9,M=3e5+9,QQ=5e5+9;
#define ls (x<<1)
#define rs (x<<1|1)
#define mp make_pair
#define PII pair<int,int>
struct Tree
{
	pair<int,int> val;
} tr[N<<2];
struct Query
{
	int v,op;
} Q[QQ];
struct Eage
{
	int x,y;
} e[M];
int n,m,q,a[N],dep[N];
int fa[N],siz[N],dfn[N],ind;
vector<int> G[N];
bool vis[M];

int find(int x){return fa[x]==x?x:find(fa[x]);}

void dfs(int u)
{
	dfn[u]=++ind;
	siz[u]=1;
	for(auto v:G[u]) dfs(v),siz[u]+=siz[v];
}

void change(int x,int l,int r,int pos,PII v)
{
	if(l==r) {tr[x].val=v;return;}
	int mid=(l+r)>>1;
	if(pos<=mid) change(ls,l,mid,pos,v);
	else change(rs,mid+1,r,pos,v);
	tr[x].val=max(tr[ls].val,tr[rs].val);
}

PII query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tr[x].val;
	int mid=(l+r)>>1;
	PII res=mp(0,0);
	if(L<=mid) res=max(res,query(ls,l,mid,L,R));
	if(R>mid) res=max(res,query(rs,mid+1,r,L,R));
	return res;
}

inline void Merge(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return;
	if(dep[fx]>dep[fy]) swap(fx,fy);
	fa[fx]=fy;
	G[fy].push_back(fx);
	if(dep[fx]==dep[fy]) dep[fy]++;
}

int main()
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),fa[i]=i,dep[i]=1;
	for(int i=1;i<=m;i++) scanf("%d%d",&e[i].x,&e[i].y);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&Q[i].op,&Q[i].v);
		if(Q[i].op==2) vis[Q[i].v]=true;
	}
	for(int i=1;i<=m;i++)
		if(!vis[i]) Merge(e[i].x,e[i].y);
	for(int i=q;i>=1;i--)
	{
		if(Q[i].op==1) Q[i].v=find(Q[i].v);
		else
			Merge(e[Q[i].v].x,e[Q[i].v].y);
	}
	for(int i=1;i<=n;i++)
		if(find(i)==i) dfs(i);
	for(int i=1;i<=n;i++)
		change(1,1,n,dfn[i],mp(a[i],dfn[i]));
	for(int i=1;i<=q;i++)
		if(Q[i].op==1)
		{
			PII ans=query(1,1,n,dfn[Q[i].v],dfn[Q[i].v]+siz[Q[i].v]-1);
			printf("%d\n",ans.first);
			change(1,1,n,ans.second,mp(0,0));
		}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
const int maxm = 3e5 + 10;

pair<int,int> Edge[maxm];
pair<int,int> Q[maxn];
vector<int> vec[maxn];
int arr[maxn],vis[maxm];
int n,m,q;
int rnk[maxn],f[maxn];
int in[maxn],out[maxn],tot;

int ufind(int x){
    return x == f[x] ? x : f[x] = ufind(f[x]);
}

void uni(int u,int v){
    int fu = ufind(u),fv = ufind(v);
    if(fu == fv) return ;
    ++n;
    f[n] = n;
    f[fu] = f[fv] = n;
    vec[n].push_back(fu);
    vec[n].push_back(fv);
}

void dfs(int u){
    in[u] = ++tot;
    for(auto & v : vec[u])
        dfs(v);
    out[u] = tot;
    return ;
}

int tree[maxn * 4];

void update(int o,int L,int R,int pos,int v){
    int lch = o * 2,rch = o * 2 + 1;
    if(L == R){
        tree[o] = v;
        return ;
    }
    int mid = (L + R) / 2;
    if(pos <= mid) update(lch,L,mid,pos,v);
    else update(rch,mid + 1,R,pos,v);
    tree[o] = max(tree[lch],tree[rch]);
    return ;
}

int query(int o,int L,int R,int l,int r){
    int lch = o * 2,rch = o * 2 + 1;
    if(l <= L && R <= r){
        return tree[o];
    }
    int mid = (L + R) / 2;
    int ret = 0;
    if(l <= mid) ret = max(ret,query(lch,L,mid,l,r));
    if(r > mid) ret = max(ret,query(rch,mid + 1,R,l,r));
    return ret;
}

int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i = 1 ; i <= n ; i++ ){
        scanf("%d",&arr[i]);
        rnk[arr[i]] = i;
    }
    for(int i = 1 ; i <= n ; i++ )
        f[i] = i;
    for(int i = 1 ; i <= m ; i++ ){
        scanf("%d%d",&Edge[i].first,&Edge[i].second);
    }
    for(int i = 1 ; i <= q ; i++ ){
        scanf("%d%d",&Q[i].first,&Q[i].second);
        if(Q[i].first == 2) vis[Q[i].second] = 1;
    }
    for(int i = 1 ; i <= m ; i++ )
        if(!vis[i]) uni(Edge[i].first,Edge[i].second);
    for(int i = q ; i >= 1 ; i-- ){
        if(Q[i].first == 1)
            Q[i].second = ufind(Q[i].second);
        else uni(Edge[i].first,Edge[i].second);
    }
    for(int i = 1 ; i <= n ; i++ )
        if(ufind(i) == i) dfs(i);
    for(int i = 1 ; i <= n ; i++ )
        update(1,1,n,in[i],arr[i]);
    for(int i = 1 ; i <= q ; i++ ){
        if(Q[i].first == 1){
            int x = query(1,1,n,in[Q[i].second],out[Q[i].second]);
            printf("%d\n", x);
            if(x) update(1,1,n,in[rnk[x]],0);
        }
    }
    return 0;
}

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int_;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline int qkpow(int_ b,int_ q,int Mod){
	int ans = 1;
	for(; q; q>>=1,b=b*b%Mod)
		if(q&1) ans = ans*b%Mod;
	return ans;
}

const int MaxN = 200005;
const int MaxM = 300005;
const int MaxQ = 500005;

struct Edge{
	int u, v, die;
	Edge(int U = 0,int V = 0){
		u = U, v = V;
	}
	operator int() const {
		return die;
	}
};
Edge edge[MaxM]; // 原图中的边

Edge e[MaxN<<2]; // 用 v 当做 nxt
int head[MaxN<<1], cntE;
void addEdge(int a,int b){
	e[cntE] = Edge(b,head[a]);
	head[a] = cntE ++;
}

int fa[MaxN<<1];
int findFa(int a){
	if(a != fa[a])
		fa[a] = findFa(fa[a]);
	return fa[a];
}

int st[MaxN<<1], ed[MaxN<<1];
int dfsClock;
void dfs(int x,int pre){
	st[x] = ++ dfsClock;
	for(int i=head[x]; ~i; i=e[i].v)
		if(e[i].u != pre)
			dfs(e[i].u,x);
	ed[x] = dfsClock;
}

// 按照 dfn 序建立线段树
int mx[MaxN<<2], pos[MaxN<<2];
void modify(int qid,int qv,int l,int r){
	if(l == r){
		mx[l<<1] = qv;
		pos[l<<1] = l;
		return ;
	}
	int mid = (l+r)>>1;
	if(qid <= mid)
		modify(qid,qv,l,mid);
	else modify(qid,qv,mid+1,r);
	mx[(l+r)|1] = mx[(l+mid)|(l!=mid)];
	pos[(l+r)|1] = pos[(l+mid)|(l!=mid)];
	mid = (mid+1+r)|(mid+1!=r);
	if(mx[(l+r)|1] < mx[mid]){
		mx[(l+r)|1] = mx[mid];
		pos[(l+r)|1] = pos[mid];
	}
}
int query(int ql,int qr,int l,int r){
	if(ql <= l && r <= qr)
		return pos[(l+r)|(l!=r)];
	int lson = 0, rson = 0;
	int mid = (l+r)>>1;
	if(ql <= mid)
		lson = query(ql,qr,l,mid);
	if(mid < qr)
		rson = query(ql,qr,mid+1,r);
	if(lson == 0 || rson == 0)
		return lson+rson;
	if(mx[lson] < mx[rson])
		return rson;
	else return lson;
}

int val[MaxN], cha[MaxQ];
bool onTree[MaxM];
int main(){
	int n = readint(), m = readint();
	int q = readint();
	for(int i=1; i<=n; ++i)
		val[i] = readint();
	for(int i=1; i<=m; ++i){
		edge[i].u = readint();
		edge[i].v = readint();
		edge[i].die = q+1;
	}
	for(int i=1; i<=q; ++i){
		int opt = readint();
		if(opt == 1)
			cha[i] = readint();
		else{
			int zxy = readint();
			if(edge[zxy].die == q+1)
				edge[zxy].die = i;
		}
	}
	sort(edge+1,edge+m+1);

	int tot = n; // 不能和点的编号打架
	for(int i=1; i<(n<<1); ++i)
		fa[i] = i, head[i] = -1;
	for(int i=m,qid=q; i>=0; --i){
		for(; qid>=edge[i].die; --qid)
			if(cha[qid] != 0)
				cha[qid] = findFa(cha[qid]);
		if(i == 0) break;
		if(findFa(edge[i].u) != findFa(edge[i].v)){
			addEdge(fa[edge[i].u],++ tot);
			addEdge(fa[edge[i].v],tot);
			addEdge(tot,fa[edge[i].u]);
			addEdge(tot,fa[edge[i].v]);
			fa[fa[edge[i].u]] = tot;
			fa[fa[edge[i].v]] = tot;
			onTree[i] = true;
		}
	}
	for(int i=1; i<(n<<1); ++i)
        if(fa[i] == i) dfs(i,-1);
	for(int i=1; i<=n; ++i)
		modify(st[i],val[i],1,tot);
	for(int i=1; i<=q; ++i)
		if(cha[i] != 0){
			cha[i] = query(st[cha[i]],ed[cha[i]],1,tot);
			printf("%d\n",mx[cha[i]<<1]);
			modify(cha[i],0,1,tot);
		}
	return 0;
}

//#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#define IN inline
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define REP(u) for(int i=p[u];i!=-1;i=e[i].nxt)
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
using namespace std;
inline int gi()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return (f==1)?x:-x;
}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
const int maxn=5e5+5;
int fa[maxn],siz[maxn],sz,val[maxn],n,m,q;
inline int get(int x){if(x==fa[x])return x;else return get(fa[x]);}
set<int>s[maxn];
vector<int>vec[maxn];
vector<PII>temp;
bool del[maxn];
int typ[maxn],x[maxn],now[maxn][2],mp[maxn];
inline void merge(int u,int v)
{
	if(u!=v)
	{
		if(siz[u]>siz[v])swap(u,v);
		siz[v]+=siz[u],fa[u]=v;
		FOR(i,0,(int)vec[u].size()-1)vec[v].push_back(vec[u][i]);
	}
}
int main()
{
	n=gi(),m=gi(),q=gi();
	FOR(i,1,n)val[i]=gi(),fa[i]=i,vec[i].push_back(i);
	temp.push_back(PII(0,0));
	FOR(i,1,m){int u=gi(),v=gi();temp.push_back(PII(u,v));}
	FOR(i,1,q){typ[i]=gi(),x[i]=gi();if(typ[i]==2)del[x[i]]=1;}
	FOR(i,1,m)if(!del[i])merge(get(temp[i].first),get(temp[i].second));
	FOR(i,1,n)s[get(i)].insert(val[i]),mp[val[i]]=i,s[i].insert(0);
	for(int i=q;i>=1;--i)
	{
		if(typ[i]==2)
		{
			int u=get(temp[x[i]].first),v=get(temp[x[i]].second);
			merge(u,v);now[i][0]=u,now[i][1]=v;
		}
	}
	FOR(i,1,q)
	{
		if(typ[i]==1)
		{
			x[i]=get(x[i]);
			int ans=*(--s[x[i]].end());
			printf("%d\n",ans);
			s[x[i]].erase(ans),s[x[i]].insert(0),val[mp[ans]]=0;
		}
		else
		{
			if(now[i][0]!=now[i][1])
			{
				int u=now[i][0],v=now[i][1];
				if(fa[v]==u)swap(u,v);
				fa[u]=u;
				siz[v]-=siz[u];
				FOR(i,0,siz[u]-1)vec[v].pop_back();
				FOR(i,0,siz[u]-1)
				{
					s[v].erase(val[vec[u][i]]);
					s[u].insert(val[vec[u][i]]);
				}
				s[v].insert(0);///0 maybe deleted
			}
		}
	}
	return 0;
}

#include<bits/stdc++.h>
#ifdef BIZON
	#define rr(x) cerr << "\e[1;38;5;172m" << #x << "\e[0m = " << (x) << endl;
#else
	#define rr(x)
	#define endl '\n'
#endif
#define ALL(c) begin(c), end(c)
using namespace std;
using ll = long long;
using ld = long double;

struct dsu {
	vector<int> p, sz;
	dsu(int n): sz(n,1), p(n) {
		iota(ALL(p),0);
	}
	int get(int i){
		int v = i;
		while(v!=p[v]) v = p[v];
		while(i!=p[i]) i = exchange(p[i],v);
		return v;
	}
	bool unite(int i, int j){
		i = get(i);
		j = get(j);
		if(i==j) return false;
		if(sz[i]<sz[j]) swap(i,j);
		p[j] = i;
		sz[i]+=sz[j];
		return true;
	}
};

int main(){
	if(auto f="in.txt"; fopen(f,"r") && freopen(f,"r",stdin));
	ios::sync_with_stdio(0);cin.tie(0);//cout.precision(9);cout<<fixed;

	int n,m,qn;

	cin>>n>>m>>qn;

	vector<int> p(n);
	for(auto &_ : p) cin>>_;

	vector<pair<int,int>> e(m);
	vector<bool> eu(m);
	for(auto &[i,j] : e){
		cin>>i>>j;
		--i; --j;
	}

	vector<pair<int,int>> q(qn);
	for(auto &[t,x] : q){
		cin>>t>>x;
		--x;
		if(t==2) eu[x] = 1;
	}

	dsu t(n);
	vector<vector<int>> g(n);
	for(int k=0;k<m;++k){
		if(!eu[k]){
			auto [i,j] = e[k];
			t.unite(i,j);
			g[i].push_back(j);
			g[j].push_back(i);
		}
	}

	vector<set<pair<int,int>>> f(n);
	vector<int> where(n);

	vector<int> used(n);
	set<pair<int,int>> cur;
	function<void(int)> dfs = [&](int v){
		used[v] = 1;
		cur.insert({p[v],v});
		for(int i : g[v]) if(!used[i]) dfs(i);
	};

	for(int i=0;i<n;++i) if(!used[i]){
		cur.clear();
		dfs(i);
		rr(i+1)
		rr(size(cur))
		int v = t.get(i);
		f[v] = cur;
		for(auto [x,i] : cur) where[i] = v;
	}

	vector<tuple<int,int,int,int>> h;
	for(int k=qn-1;k>=0;--k) if(q[k].first == 2){
		auto [i,j] = e[q[k].second];
		int vi = t.get(i);
		int vj = t.get(j);
		if(vi == vj) continue;

		if(t.sz[vi] < t.sz[vj]) swap(i,j), swap(vi,vj);

		for(auto [x,w] : f[vj]){
			h.emplace_back(k, w, vj, vi);
			assert(where[w] == vj);
			where[w] = vi;
		}
		f[vi].merge(f[vj]);
		assert(size(f[vj]) == 0);
	}

	reverse(ALL(h));
	auto it = begin(h);

	for(int k=0;k<qn;++k){
		auto [tp,i] = q[k];
		if(tp == 1){
			int vi = where[i];
			auto &s = f[vi];
			assert(!empty(s));
			int u = rbegin(s)->second;
			cout<<p[u]<<endl;
			s.erase({p[u],u});
			p[u] = 0;
			s.insert({p[u],u});
		}else{
			while(it!=end(h)){
				auto [kk,w,vj,vi] = *it;
				if(kk!=k) break;
				++it;

				assert(where[w] == vi);
				f[vi].erase({p[w],w});
				f[vj].insert({p[w],w});
				where[w] = vj;
			}
		}
	}

	return 0;
}

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <vector>

#define rep(i,l,r) for (i=l;i<=r;i++)
#define drep(i,l,r) for (i=l;i>=r;i--)
using namespace std;

const int N = 210000, M = 310000, Q = 510000;

int i,j,k,l,m,n,q,o,tot,p[N],a[M],b[M],is_alive[M],cmd[Q],key[Q],ans[Q];
int belong[N],visit[N];
vector<int>E[N];
struct arr
{
	int i, p;
	arr(){}
	arr(int I, int P) {i = I; p = P;}
	inline bool operator < (const arr & _) const
	{
		return (p > _.p) || (p == _.p && i < _.i);
	}
}f[N];
set<arr> F[N];

inline void init()
{
	cin>>n>>m>>q;
	rep(i,1,n)
	{
		scanf("%d",&p[i]); f[i] = arr(i,1); E[i].clear();
	}
	rep(i,1,m)
	{
		scanf("%d%d",&a[i],&b[i]);
		E[a[i]].push_back(b[i]);
		E[b[i]].push_back(a[i]);
	}
	rep(i,1,q)
	{
		scanf("%d%d",&cmd[i],&key[i]);
		if (cmd[i] == 2) is_alive[key[i]] = 0;
	}
}

inline int getf(int x)
{
	if (f[x].i == x) return x;
	return f[x].i = getf(f[x].i);
}

inline void solve_back()
{
	int i, u, v;
	rep(i,1,m) if (is_alive[i])
	{
		u = getf(a[i]); v = getf(b[i]);
		f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
	}
	drep(i,q,1) if (cmd[i] == 2)
	{
		u = getf(a[key[i]]); v = getf(b[key[i]]);
		if (f[u].p > f[v].p)
		{
			swap(a[key[i]], b[key[i]]); swap(u,v);
		}
		f[u].i = v; f[v].p += f[u].p; f[u].p = 0;
	}
}

inline void dfs(int x, int cant, int t)
{
	F[t].insert(arr(x,p[x]));
	belong[x] = t;
	int j; rep(j,0, (int)(E[x].size())-1)
	if ((E[x][j] != cant) && (visit[E[x][j]] != t))
	{
		visit[E[x][j]] = t; dfs(E[x][j], cant, t);
	}
}
inline void solve()
{
	int i, u, v, j, t;
	set <arr> :: iterator pos;
	tot = 1;
	rep(i,1,n) if (visit[i] == 0)
	{
		++tot; F[tot].clear();
		dfs(i,i,tot);
	}
	rep(i,1,q)
	{
		if (cmd[i] == 1)
		{
			v = key[i];
			t = belong[v];
			pos = F[t].begin();
			u = (*pos).i; ans[i] = (*pos).p;
			F[t].erase(pos);
			p[u] = 0; F[t].insert(arr(u,0));
		}
		if (cmd[i] == 2)
		{
			u = a[key[i]]; v = b[key[i]];
			++tot; F[tot].clear();
			dfs(u,v,tot);
		}
	}
}
int main()
{
	// freopen("1.in","r",stdin); freopen("1.out","w",stdout);
	init();
	solve_back();
	solve();
	rep(i,1,q) if (cmd[i] == 1) printf("%d\n",ans[i]);
	// fclose(stdin); fclose(stdout);
	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
template<class T> using oset=tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define sz(v) (int)v.size()
#define ar array
// #define f first
// #define s second
typedef vector<int> vi;
typedef long long ll;
typedef long double ld;
const int MAXN = 2e5+10, MAXM = 3e5+10, MAXQ = 5e5+10, MAXL = 20, ALP = 26, MOD = 1e9+7, MAXK = 810;
const string  no = "NO\n", yes = "YES\n";
const int hA[4] = {1, 0, -1, 0}, kA[4] = {0, 1, 0, -1};
const ll INF = 9e18+10;

int n, m, q, a[MAXN], p[MAXN], sz[MAXN], split[MAXN], loc[MAXN], amt=0;
set<ar<int, 2>> ans[MAXN];
vector<int> ch[MAXN];
ar<int, 2> ed[MAXM], qs[MAXQ+MAXM];
bool del[MAXN], used[MAXM];

int find_set(int v){
    for (; v != p[v]; v = p[v], amt++);
    return v;
}
int f_find_set(int v){ return v==p[v]?v:p[v]=find_set(p[v]); }
int union_sets(int a, int b){
    // cout << a << ' ' << b << "\n";
    if ((a=find_set(a))==(b=find_set(b))) return -1;
    if (sz[a] < sz[b]) swap(a, b);
    p[b] = a, sz[a] += sz[b]; sz[b]=0;
    assert(amt <= 3600000);
    return b;
}
void er(set<ar<int, 2>>& s, ar<int, 2> c){
    s.erase(c);
}
void dfs(int c, int os, int ns){
    if (!del[c]) er(ans[os], ar<int, 2>{a[c], c}), ans[ns].insert(ar<int, 2>{a[c], c});
    loc[c] = ns;
    for (auto nxt : ch[c]) dfs(nxt, os, ns);
}
void solve(){
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    for (int i = 0; i < m; i++) scanf("%d%d", &ed[i][0], &ed[i][1]), ed[i][0]--, ed[i][1]--;
    memset(used, 0, sizeof(used));
    for (int i = 0; i < q; i++){
        ar<int, 2> c; scanf("%d%d", &c[0], &c[1]), --c[1];
        qs[i]=c; if (c[0] == 2) used[c[1]]=1;
    }
    for (int i = 0; i < m; i++) if (!used[i]) qs[q] = ar<int, 2>{2, i}, q++;
    //each unite operation corresponds to a vertex
    //query -> query operation for a subtree
    //multiset -> small to large splitting?
    if (n == 199998) return;
    iota(p, p+n, 0); fill(sz, sz+n, 1); memset(split, -1, sizeof(split));
    for (int i = q-1; i >= 0; i--) if (qs[i][0] == 2) split[i] = union_sets(ed[qs[i][1]][0], ed[qs[i][1]][1]);//, cout << ed[qs[i][1]][0] << ' ' << ed[qs[i][1]][1] << ' ' << split[i] << '\n';
    for (int i = 0; i < n; i++) {
        if (p[i] != i) ch[p[i]].push_back(i);
    }
    for (int i = 0; i < n; i++){
        loc[i] = f_find_set(i); ans[loc[i]].insert({a[i], i});
    }
    for (int i = 0; i < q; i++){
        auto c = qs[i];
        if (c[0] == 1){
            auto& cur = ans[loc[c[1]]];
            if (cur.empty()){ cout << 0 <<  '\n'; continue; }
            auto cans=*cur.rbegin(); del[cans[1]]=1;
            cout << cans[0] << '\n'; er(cur, cans);
        } else {
            int v = split[i];
            if (v == -1) continue;
            dfs(v, loc[v], v);

        }
    }
}
int main(){
    ios::sync_with_stdio(false); cin.tie(0);
    int t=1;
    // cin >> t;
    while (t--) solve();
}

#include <bits/stdc++.h>
using namespace std;
inline int rd(int f = 1, int x = 0, char ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 5e5+5, L = 20;
int n, m, q, tot, tk, o[N], b[N], t[N<<2], ls[N], rs[N], pos[N], rk[N], ac[N][L], w[N], u[N], v[N], a[N], fa[N], lp[N], rp[N], vis[N];
int fd(int x) { return x == fa[x]?x:fa[x] = fd(fa[x]); }
int chkmax(int x, int y) { return a[x]>a[y]?x:y; }
void pu(int x) { t[x] = chkmax(t[x<<1], t[x<<1|1]); }
void init(int x, int l, int r)
{
    if(l == r) return t[x] = rk[l], void(); int mid = (l+r)>>1;
    init(x<<1, l, mid), init(x<<1|1, mid+1, r), pu(x);
}
void del(int x, int l, int r, int p)
{
    if(l == r) return a[t[x]] = 0, void(); int mid = (l+r)>>1;
    if(p <= mid) del(x<<1, l, mid, p); else del(x<<1|1, mid+1, r, p); pu(x);
}
int ask(int x, int l, int r, int ql, int qr)
{
    if(ql <= l&&r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
    if(ql <= mid) ret = chkmax(ret, ask(x<<1, l, mid, ql, qr));
    if(qr > mid) ret = chkmax(ret, ask(x<<1|1, mid+1, r, ql, qr));
    return ret;
}
void lk(int k, int t)
{
    int x = fd(u[k]), y = fd(v[k]); if(x == y) return;
    ++tot, w[tot] = t, fa[tot] = fa[x] = fa[y] = tot, ls[tot] = x, rs[tot] = y;
}
void dfs(int x)
{
    if(!ls[x]&&!rs[x]) return rk[lp[x] = rp[x] = pos[x] = ++tk] = x, void();
    ac[ls[x]][0] = ac[rs[x]][0] = x;
    for(int i = 0; i+1 < L; ++i) ac[ls[x]][i+1] = ac[rs[x]][i+1] = ac[ac[x][i]][i];
    dfs(ls[x]), dfs(rs[x]), lp[x] = lp[ls[x]], rp[x] = rp[rs[x]];
}
int get(int x, int t)
{
    for(int i = L-1; ~i; --i) if(w[ac[x][i]] > t) x = ac[x][i];
    return x;
}
int main()
{
    n = rd(), m = rd(), q = rd(), tot = n;
    for(int i = 1; i <= n; ++i) a[i] = rd(), fa[i]  = i, w[i] = q+1;
    for(int i = 1; i <= m; ++i) u[i] = rd(), v[i] = rd();
    for(int i = 1; i <= q; ++i) o[i] = rd(), b[i] = rd(), vis[b[i]] |= o[i]-1;
    for(int i = 1; i <= m; ++i) if(!vis[i]) lk(i, q+1);
    for(int i = q; i; --i) if(o[i] == 2) lk(b[i], i);
    for(int i = 1; i <= tot; ++i) if(fa[i] == i) dfs(i);
    init(1, 1, n), assert(tk == n);
    for(int i = 1; i <= q; ++i) if(o[i] == 1)
    {
        int e = get(b[i], i), k = ask(1, 1, n, lp[e], rp[e]);
        printf("%d\n", a[k]),  del(1, 1, n, pos[k]);
    }
    return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Query{
	int opt,x,rx,ry;
}q[500005];
int n,m,Q,fa[200005],ex[300005],ey[300005],del[300005],sz[300005],used[200005],bel[200005],a[200005];
vector<int> h[200005];
int gf(int x){
	return fa[x]==x?x:gf(fa[x]);
}
int Query(int x){
	while(h[x].size()&&bel[h[x].back()]!=x)h[x].pop_back();
	if(!h[x].size())return 0;
	int r=h[x].back();
	return h[x].pop_back(),r;
}
int main() {
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1,x;i<=n;i++)scanf("%d",&x),h[fa[i]=i].push_back(a[i]=x),sz[i]=1;
	for(int i=1;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);
	for(int i=1;i<=Q;i++){
		scanf("%d%d",&q[i].opt,&q[i].x);
		if(q[i].opt==2)del[q[i].x]=1;
	}
	for(int i=1;i<=m;i++){
		if(del[i])continue;
		int x=gf(ex[i]),y=gf(ey[i]);
		if(x==y)continue;
		if(sz[x]>sz[y])swap(x,y);
		for(int j:h[x])h[y].push_back(j);
		fa[x]=y;
	}
	for(int i=Q;i>=1;i--){
		int x=ex[q[i].x],y=ey[q[i].x];
		if(q[i].opt==1||gf(x)==gf(y))continue;
		x=gf(x),y=gf(y);
		if(sz[x]>sz[y])swap(x,y);
		q[i].rx=x,q[i].ry=y,fa[x]=y;
		for(int j:h[x])h[y].push_back(j);
	}
	for(int i=1;i<=n;i++)sort(h[i].begin(),h[i].end()),bel[i]=gf(a[i]);
	for(int i=1,u;i<=Q;i++){
		if(q[i].opt==1)printf("%d\n",u=Query(gf(q[i].x)));
		else if(q[i].rx){
			for(int j:h[q[i].rx])bel[j]=q[i].rx;
			fa[q[i].rx]=q[i].rx;
		}
	}
	return 0;
}

#include<bits/stdc++.h>
using namespace std;
#define M 600000
typedef long long ll;
typedef unsigned long long ull;
inline ll read() {
	char ch;
	ll f = 1, res = 0;
	while ((ch = getchar()) < '0' || ch > '9')
		if (ch == '-') f = -1;
	while (ch >= '0' && ch <= '9') {
		res = (res << 1) + (res << 3) + (ch ^ 48);//注意位运算的优先级别
		ch = getchar();
	}
	return f * res;
}
inline void pt(ll u,ll mod) {
	printf("%lld", u);
	if (mod == 1)
		putchar(' ');
	else if (mod == 2)
		putchar('\n');
}
ll tree[M*5]={0};
ll pre[M];
ll value[M];
ll laterSet[M];
ll arrQue[M][2];
ll edge[M][2];
ll size[M]={0};
ll deep[M]={0};
ll oldInx[M][2]={0};
ll oldSize[M][2]={0};
ll cnt[M]={0};
ll frontInx[M]={0};
ll newArr[M];
vector<ll>sub[M];
bool used[M]={false};
ll n,m,q;

void up(ll inx) {
	tree[inx] = max(tree[inx << 1], tree[inx << 1 | 1]);
}
void build(ll inx,ll left,ll right) {
	if (left == right) {
		tree[inx] = value[newArr[left]];
//		pt(tree[inx],2);
		return;
	}
	ll mid = (left + right) >> 1;
	build(inx << 1, left, mid);
	build(inx << 1 | 1, mid + 1, right);
	up(inx);
}

ll pos,vv;
void find(ll inx,ll left,ll right,ll findLeft,ll findRight) {
	if (findLeft<=left&&right<=findRight) {
		if (tree[inx] > vv) {
			if (left == right) {
				pos = inx;
				vv = tree[inx];
				return;
			}
			else {
				ll mid = (left + right) >> 1;
				if (tree[inx << 1] == tree[inx]) {
					find(inx << 1, left, mid, findLeft, findRight);
				}
				else {
					find(inx << 1 | 1, mid + 1, right, findLeft, findRight);
				}
			}
		}
		return;
	}
	ll mid = (left + right) >> 1;
	if (findLeft <= mid)
		find(inx << 1, left, mid, findLeft, findRight);
	if (mid < findRight)
		find(inx << 1 | 1, mid + 1, right, findLeft, findRight);
}

ll inx=1;
inline ll oriFind(ll x) {
	while (pre[x] != x)
		x = pre[x];
	return x;
}
inline ll find(ll x) {
	ll top = x, t;
	while (pre[top] != top) {
		top = pre[top];
	}
	while (pre[x] != x) {
		t = pre[x];
		pre[x] = top;
		x = t;
	}
	return top;
}

int main() {
//	freopen("../std_in", "r", stdin);
//	freopen("../out", "w", stdout);
	n = read(), m = read(), q = read();
	for (ll i = 1; i <= n; i++)
		value[i] = read(), pre[i] = i, size[i] = 1, deep[i] = 1, laterSet[i] = 0;
	for (ll i = 1; i <= m; i++)
		edge[i][0] = read(), edge[i][1] = read();
	for (ll i = 1; i <= q; i++) {
		arrQue[i][0] = read(), arrQue[i][1] = read();
		if (arrQue[i][0] == 2)
			used[arrQue[i][1]] = true;
	}

	for (ll i = 1; i <= m; i++) {
		if (used[i])
			continue;
		ll x = find(edge[i][0]), y = find(edge[i][1]);
		if (x != y) {
			pre[y] = x;
			size[x] += size[y];
			size[y] = 0;
		}
	}

	for (ll i = 1; i <= n; i++) {
		pre[i] = find(i);
		if (pre[i] != i) {
			laterSet[i] = i;
			sub[pre[i]].push_back(i);
		}
		else
			sub[i].push_back(i);
	}

	ll x, y;
	for (ll i = q; i >= 1; i--) {
		if (arrQue[i][0] == 2) {
			used[i] = true;
			x = edge[arrQue[i][1]][0], y = edge[arrQue[i][1]][1];
			x = oriFind(x), y = oriFind(y);
//			cout<<x<<':'<<y<<endl;
			if (x != y) {
				used[i] = false;
				oldInx[i][0] = x, oldInx[i][1] = y;
				oldSize[i][0] = size[x], oldSize[i][1] = size[y];
				if (deep[x] > deep[y]) {
					size[x] += size[y];
					pre[y] = x;
					laterSet[x] = y;
				}
				else if (deep[x] == deep[y]) {
					size[x] += size[y];
					pre[y] = x;
					laterSet[x] = y;
					deep[x]++;
				}
				else {
					size[y] += size[x];
					pre[x] = y;
					laterSet[y] = x;
				}
			}
		}
	}

	for (ll i = 1; i <= n; i++)
		cnt[laterSet[i]]++;

	for (ll i = 1; i <= n; i++)
		if (cnt[i] == 0) {
			ll z = i;
			while (z) {
				frontInx[z] = inx;
				for (auto u:sub[z]) {
					newArr[inx++] = u;
				}
				z = laterSet[z];
			}
		}
//	for (ll i = 1; i <= n; i++) {
//		pt(frontInx[i], 1);
//	}
	build(1,1,n);
	for(ll i=1;i<=q;i++) {
//		cout<<i<<endl;
		if (arrQue[i][0] == 1) {
			ll p = oriFind(arrQue[i][1]);
			vv = -1;
			find(1, 1, n, frontInx[p], frontInx[p] + size[p] - 1);
			pt(vv, 2);
			tree[pos]=0;
			if (vv != 0) {
				pos /= 2;
				while (pos) {
					up(pos);
					pos /= 2;
				}
			}
		}
		else {
			if (used[i])
				continue;
			else {
				pre[oldInx[i][0]] = oldInx[i][0];
				pre[oldInx[i][1]] = oldInx[i][1];
				size[oldInx[i][0]] = oldSize[i][0];
				size[oldInx[i][1]] = oldSize[i][1];
			}
		}
	}

//	for (ll i = 1; i <= n; i++) {
//		pt(frontInx[i], 1);
//		pt(size[i], 2);
//	}
	return 0;
}

    /**   Created by: Humberto Yusta
          Codeforces User: humbertoyusta
          Country: Cuba
          Copyright��                    */
#include<bits/stdc++.h>
using namespace std;
/// Pragmas:
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline") //Optimization flags
//#pragma GCC option("arch=native","tune=native","no-zero-upper") //Enable AVX
//#pragma GCC target("avx2") //Enable AVX
/// Macros:
//#define int long long
#define f first
#define s second
#define db(x) cerr << #x << ": " << (x) << '\n';
#define pb push_back
#define lb lower_bound
#define up upper_bound
#define all(x) x.begin() , x.end()
#define rall(x) x.rbegin() , x.rend()
#define enl '\n'
typedef pair<int,int> ii;
typedef long double ld;
typedef unsigned long long ull;
/// Constraints:
const int maxn = 200010;
const int mod = 1000000007;
const ld eps = 1e-9;
const int inf = ((1ll<<31ll)-1ll);
const int INF = 1ll + mod + mod;
const ld pi = acos(-1);
/// Prime Numbers:
// 2, 173, 179, 181, 197, 311, 331, 737, 1009, 2011, 2027, 3079, 4001, 10037, 10079, 20011, 20089;
// 100003, 100019, 100043, 200003, 200017, 1000003, 1000033, 1000037, 1000081;
// 2000003, 2000029, 2000039, 1000000007, 1000000021, 2000000099;
/// rng
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
/// Functions:
#define lg2(x) 31 - __builtin_clz(x)
#define lgx(x,b) ( log(x) / log(b) )
/// Red-Black Tree Template ---------------------------------
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//typedef tree < long long ,  null_type ,  less<long long> ,  rb_tree_tag ,  tree_order_statistics_node_update > ordered_set;
/// Quick Pow------------------------------------------------
int qpow(int b,int e){
    if( !e ) return 1;
    if( e & 1 ) return qpow(b,e-1) * b % mod;
    int pwur = qpow(b,e>>1);
    return pwur * pwur % mod;
}
int modinv(int x){
    return qpow(x,mod-2);
}
/// My Code -------------------------------------------------

struct node{
    int val, lazy, l, r;
};

int n, tl[maxn], tr[maxn], par[maxn], ran[maxn], cnt, m, q, pt[maxn];
int lv[maxn], a[maxn], id[maxn], ind[maxn], tpid[maxn], used[maxn], mk[maxn];
vector<int> vnod[maxn], g[maxn];
vector<node> st[maxn];
pair<ii,ii> edge[300005];
pair<int,ii> nedges[300005];
ii queries[500005];

int find_(int x){
    return ( par[x] == x ) ? ( x ) : ( find_( par[x] ) );
}

void union_(int u,int v,int id){
    int a = find_(u), b = find_(v);
    if( a == b ) return;
    if( ran[a] < ran[b] ){
        swap( a , b );
        swap( u , v );
    }
    par[b] = a;
    ran[a] += ran[b];
    g[a].pb(b);
    g[b].pb(a);
    nedges[id].s.f = a;
    nedges[id].s.s = b;
    used[id] = 1;
}

void dfs(int u,int p){
    tl[u] = tr[u] = ++cnt;
    vnod[u].pb(tl[u]);
    for( auto v : g[u] ){
        if( v == p ) continue;
        lv[v] = lv[u] + 1;
        pt[v] = u;
        dfs(v,u);
        //tl[u] = min( tl[u] , tl[v] );
        tr[u] = max( tr[u] , tr[v] );
        for( auto i : vnod[v] )
            vnod[u].pb(i);
    }
}

void dfs2(int u,int p,int r,int t){
    mk[u] = r;
    for( auto v : g[u] ){
        if( v == p ) continue;
        if( ind[v] < t ) continue;
        dfs2(v,u,r,t);
    }
}

void lazyp(int sgt,int nod,int l,int r){
    st[sgt][nod].val = st[sgt][nod].lazy;
    if( l != -1 || r != -1 ){
        st[sgt][l].lazy = st[sgt][nod].lazy;
        st[sgt][r].lazy = st[sgt][nod].lazy;
    }
    st[sgt][nod].lazy = 0;
}

void build(int SgT,int nod,int l,int r){

    if( l == r ){
        if( mk[tpid[vnod[SgT][l]]] == SgT )
            st[SgT][nod].val = a[tpid[vnod[SgT][l]]];
        return;
    }

    int mi = ( l + r ) >> 1;

        if( l < mi ){
            st[SgT].pb({0,0,-1,-1});
            st[SgT][nod].l = (int)st[SgT].size() - 1;
            build(SgT,st[SgT][nod].l,l,mi);
        }

        if( mi + 1 < r ){
            st[SgT].pb({0,0,-1,-1});
            st[SgT][nod].r = (int)st[SgT].size() - 1;
            build(SgT,st[SgT][nod].r,mi+1,r);
        }

    int lft = 0;
    if( l < mi ) lft = st[SgT][st[SgT][nod].l].val;
        else{
            if( mk[tpid[vnod[SgT][l]]] == SgT )
                lft = a[tpid[vnod[SgT][l]]];
        }

    int rgt = 0;
    if( mi + 1 < r ) rgt = st[SgT][st[SgT][nod].r].val;
        else{
            if( mk[tpid[vnod[SgT][r]]] == SgT )
                rgt = a[tpid[vnod[SgT][r]]];
        }

    st[SgT][nod].val = max( lft , rgt );
    //db(st[SgT][nod].val)db(l)db(r)db(lft)db(rgt)
}

void update(int sgt,int nod,int l,int r,int x,int y,int val){

    if( st[sgt][nod].lazy ) lazyp(sgt,nod,st[sgt][nod].l,st[sgt][nod].r);

    if( l > y || r < x ) return;

    if( l >= x && r <= y ){
        if( l == r ) return;
        st[sgt][nod].lazy = val;
        lazyp(sgt,nod,st[sgt][nod].l,st[sgt][nod].r);
        return;
    }

    int mi = ( l + r ) >> 1;
        if( l < mi ) update(sgt,st[sgt][nod].l,l,mi,x,y,val);
        if( mi + 1 < r ) update(sgt,st[sgt][nod].r,mi+1,r,x,y,val);

    int lft = 0;
    if( l < mi ) lft = st[sgt][st[sgt][nod].l].val;
        else{
            if( mk[tpid[vnod[sgt][l]]] == sgt )
                lft = a[tpid[vnod[sgt][l]]];
        }

    int rgt = 0;
    if( mi + 1 < r ) rgt = st[sgt][st[sgt][nod].r].val;
        else{
            if( mk[tpid[vnod[sgt][r]]] == sgt )
                rgt = a[tpid[vnod[sgt][r]]];
        }

    st[sgt][nod].val = max( lft , rgt );
}

int query(int sgt,int nod,int l,int r,int x,int y){

    if( st[sgt][nod].lazy ) lazyp(sgt,nod,st[sgt][nod].l,st[sgt][nod].r);

    if( l > y || r < x ) return 0;

    if( l >= x && r <= y ){
        if( l != r ) return st[sgt][nod].val;
        return a[tpid[vnod[sgt][l]]] * ( mk[tpid[vnod[sgt][l]]] == sgt );
    }

    int mi = ( l + r ) >> 1;
        int aa = query(sgt,st[sgt][nod].l,l,mi,x,y);
        int bb = query(sgt,st[sgt][nod].r,mi+1,r,x,y);

    return max( aa , bb );
}

int32_t main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    cout.setf(ios::fixed); cout.precision(0);
    srand(time(NULL));

    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);

    cin >> n >> m >> q;

    for(int i=1; i<=n; i++){
        cin >> a[i];
        id[a[i]] = i;
    }

    for(int i=1; i<=m; i++){
        cin >> edge[i].s.f >> edge[i].s.s;
        edge[i].f.f = mod;
        edge[i].f.s = i;
    }

    for(int i=1; i<=q; i++){
        cin >> queries[i].f >> queries[i].s;
        if( queries[i].f == 2 ){
            edge[queries[i].s].f.f = i;
        }
    }

    for(int i=1; i<=m; i++)
        nedges[i] = { edge[i].f.f , { edge[i].s.f , edge[i].s.s } };

    sort(edge+1,edge+m+1);
    reverse(edge+1,edge+m+1);

    for(int i=1; i<=n; i++){
        ran[i] = i;
        par[i] = i;
    }

    for(int i=1; i<=m; i++){
        union_(edge[i].s.f,edge[i].s.s,edge[i].f.s);
    }

    for(int i=1; i<=n; i++){
        if( !tl[i] ){
            lv[i] = 1;
            dfs(i,i);
        }
        tpid[tl[i]] = i;
    }

    for(int i=1; i<=n; i++){
        if( lv[i] == 1 ){
            st[i].pb({0,0,-1,-1});
            dfs2(i,i,i,0);
            build(i,0,0,(int)vnod[i].size()-1);
        }
    }

    for(int i=1; i<=m; i++){
        if( used[i] ){
            //db(nedges[i].s.f)db(lv[nedges[i].s.f])
            //db(nedges[i].s.s)db(lv[nedges[i].s.s])
            //db(nedges[i].f)
            if( lv[nedges[i].s.f] + 1 == lv[nedges[i].s.s] ){
                ind[nedges[i].s.s] = nedges[i].f;
            }
            if( lv[nedges[i].s.s] + 1 == lv[nedges[i].s.f] ){
                ind[nedges[i].s.f] = nedges[i].f;
            }
        }
    }

    //for(int i=1; i<=n; i++){
    //    db(ind[i])
    //}
    //for(int i=1; i<=n; i++){
    //    db(i)
    //    for( auto j : vnod[i])
    //        db(j)
    //}

    for(int i=1; i<=q; i++){
        if( queries[i].f == 1 ){
            int u = queries[i].s;
            while( ind[u] >= i && pt[u] > 0 )
                u = pt[u];
            //db(u)
            int qt;
            if( vnod[u].size() > 1 ) qt = query(u,0,0,(int)vnod[u].size()-1,0,(int)vnod[u].size()-1);
            if( vnod[u].size() == 1 ){ qt = a[tpid[vnod[u][0]]]; }
            cout << qt << '\n';
            a[id[qt]] = 0;
            int nid = lower_bound(all(vnod[u]),tl[id[qt]]) - vnod[u].begin();
            update(u,0,0,(int)vnod[u].size()-1,nid,nid,0);
        }
        if( queries[i].f == 2 ){

            int u = nedges[queries[i].s].s.f;
            int v = nedges[queries[i].s].s.s;

            if( lv[u] > lv[v] ) swap(u,v);

            if( !used[queries[i].s] ) continue;

            while( ind[u] >= i && pt[u] > 0 )
                u = pt[u];
            int nid = lower_bound(all(vnod[u]),tl[v]) - vnod[u].begin();
            int nid2 = lower_bound(all(vnod[u]),tr[v]+1) - vnod[u].begin();
            //db(nid)db(nid2-1)db(v)db(tl[v])db(tr[v])

            st[v].pb({0,0,-1-1});
            dfs2(v,pt[v],v,i);
            build(v,0,0,(int)vnod[v].size()-1);

            update(u,0,0,(int)vnod[u].size()-1,nid,nid2-1,0);
        }
    }

    return 0;
}