#include using namespace std; using ll = long long; #define int ll using VI = vector; using VVI = vector; using PII = pair; #define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i) #define REP(i, n) FOR(i, 0, n) #define ALL(x) x.begin(), x.end() #define PB push_back const ll INF = (1LL<<60); const int MOD = 1000000007; template T &chmin(T &a, const T &b) { return a = min(a, b); } template T &chmax(T &a, const T &b) { return a = max(a, b); } template bool IN(T a, T b, T x) { return a<=x&&x T ceil(T a, T b) { return a/b + !!(a%b); } template ostream &operator <<(ostream& out,const pair& a){ out<<'('< ostream &operator <<(ostream& out,const vector& a){ out<<'['; REP(i, a.size()) {out< st; par[rt] = -1; depth[rt] = 0; st.emplace(rt, 0); while(!st.empty()) { int v = st.top().first; int &i = st.top().second; if(i < (int)g[v].size()) { int u = g[v][i++]; if(u == par[v]) continue; par[u] = v; depth[u] = depth[v]+1; st.emplace(u,0); } else { st.pop(); int ma = 0; for(int u: g[v]){ if(u == par[v]) continue; sub[v] += sub[u]; if(ma < sub[u]) ma = sub[u], hvy[v] = u; } } } } // 根r、c番目の木についてchainについての情報をまとめる void bfs(int r, int c) { int &k = pos; queue que; que.push(r); while(que.size()) { int h = que.front(); que.pop(); for(int i=h; i!=-1; i=hvy[i]) { type[i] = c; vid[i] = k++; inv[vid[i]] = i; head[i] = h; for(int j: g[i]) { if(j!=par[i] && j!=hvy[i]) que.push(j); } } } } // 頂点に対する処理 [u,v] 開区間なので注意!!! void for_each(int u, int v, const function& f) { while(1){ if(vid[u]>vid[v]) swap(u,v); // [max(vid[head[v]],vid[u]), vid[v]] の区間についての操作を行う f(max(vid[head[v]], vid[u]), vid[v]); if(head[u]!=head[v]) v = par[head[v]]; else break; } } // 辺に対する処理 [u,v] 開区間なので注意!!! void for_each_edge(int u, int v, const function& f) { while(1) { if(vid[u]>vid[v]) swap(u,v); if(head[u]!=head[v]) { f(vid[head[v]], vid[v]); v = par[head[v]]; } else { if(u!=v) f(vid[u]+1, vid[v]); break; } } } // 頂点u, vのLCA int lca(int u,int v){ while(1) { if(vid[u]>vid[v]) swap(u,v); if(head[u]==head[v]) return u; v = par[head[v]]; } } // 頂点u, vの距離 int distance(int u, int v){ return depth[u] + depth[v] - 2*depth[lca(u,v)]; } }; struct twoEdgeComponents { int n; vector> g; // グラフの隣接リスト vector cmp; // 頂点iがどの連結成分に属するか vector> each_bcc; // i番目の連結成分の属する頂点 vector> bridge; // i番目の橋 vector order; vector inS; stack roots, S; twoEdgeComponents() {} twoEdgeComponents(int n_) : n(n_), g(VVI(n)) {} twoEdgeComponents(vector> g_) : n(g_.size()), g(g_) {} void add_edge(int p, int q) { g[p].push_back(q); g[q].push_back(p); } void dfs(int cur, int prev, int &k) { order[cur] = ++k; S.push(cur); inS[cur] = true; roots.push(cur); for(auto to: g[cur]) { if(order[to]==0) dfs(to, cur, k); else if(to!=prev && inS[to]) { while(order[roots.top()] > order[to]) roots.pop(); } } if(cur == roots.top()) { if(prev!=-1) bridge.push_back({prev, cur}); vector bcc; while(1) { int node = S.top(); S.pop(); inS[node] = false; bcc.push_back(node); if(node==cur) break; } each_bcc.push_back(bcc); roots.pop(); } } // 二重辺連結成分分解を行う void bcc() { order.assign(n, 0); inS.assign(n, false); cmp.assign(n, -1); int k = 0; for(int i=0; i> getbcc() { vector> h(each_bcc.size(), vector()); for(auto i: bridge) { int a = cmp[i.first], b = cmp[i.second]; h[a].push_back(b); h[b].push_back(a); } return h; } }; // 遅延セグメントツリー template struct segtree { using F = function; using G = function; using H = function; using P = function; F f; G g; H h; P p; T d1; E d0; int n; vector dat, lazy; segtree(){} segtree(int n_, F f_, G g_, H h_, T d1_, E d0_, P p_=[](E a, int b){return a;}): f(f_), g(g_), h(h_), p(p_), d1(d1_), d0(d0_) { n = 1; while(n < n_) n *= 2; dat.assign(n*2, d1); lazy.assign(n*2, d0); } void build(vector v) { REP(i, v.size()) dat[i+n-1] = v[i]; for(int i=n-2; i>=0; --i) dat[i] = f(dat[i*2+1], dat[i*2+2]); } // 区間の幅がlenの節点kについて遅延評価 inline void eval(int len, int k) { if(lazy[k] == d0) return; if(k*2+1 < n*2-1) { lazy[2*k+1] = h(lazy[k*2+1], lazy[k]); lazy[2*k+2] = h(lazy[k*2+2], lazy[k]); } dat[k] = g(dat[k],p(lazy[k],len)); lazy[k] = d0; } // [a, b) T update(int a, int b, ll x, int k, int l, int r) { eval(r-l, k); if(b <= l || r <= a) return dat[k]; if(a <= l && r <= b) { lazy[k] = h(lazy[k], x); return g(dat[k], p(lazy[k],r-l)); } return dat[k] = f(update(a, b, x, 2*k+1, l, (l+r)/2), update(a, b, x, 2*k+2, (l+r)/2, r)); } T update(int a, int b, ll x) { return update(a, b, x, 0, 0, n); } // [a, b) T query(int a, int b, int k, int l, int r) { eval(r-l, k); if(a <= l && r <= b) return dat[k]; bool left = !((l+r)/2 <= a || b <= l), right = !(r <= 1 || b <= (l+r)/2); if(left&&right) return f(query(a, b, 2*k+1, l, (l+r)/2), query(a, b, 2*k+2, (l+r)/2, r)); if(left) return query(a, b, 2*k+1, l, (l+r)/2); return query(a, b, 2*k+2, (l+r)/2, r); } T query(int a, int b) { return query(a, b, 0, 0, n); } // デバッグ出力 void debug() { cout << "---------------------" << endl; int cnt = 0; for(int i=1; i<=n; i*=2) { REP(j, i) {cout << "(" << dat[cnt] << "," << lazy[cnt] << ") "; cnt++;} cout << endl; } cout << "---------------------" << endl; } }; signed main(void) { cin.tie(0); ios::sync_with_stdio(false); int n, m, q; cin >> n >> m >> q; VI a(m), b(m); twoEdgeComponents bcc(n); REP(i, m) { cin >> a[i] >> b[i]; a[i]--, b[i]--; bcc.add_edge(a[i], b[i]); } bcc.bcc(); VVI g = bcc.getbcc(); HLDecomposition hld(bcc.bridge.size()+1); for(auto i: bcc.bridge) { hld.add_edge(i.first, i.second); } hld.build(); vector> que(bcc.bridge.size()+1); auto f_ = [](int l, int r){return max(l, r);}; auto g_ = [](int l, int r){return r==-1?l:r;}; auto h_ = [](int l, int r){return r==-1?l:r;}; segtree seg(n, f_, g_, h_, -1, -1); map mp; REP(i, q) { int type; cin >> type; // 追加 if(type == 1) { int u, w; cin >> u >> w; u--; int ver = hld.vid[bcc.cmp[u]]; que[ver].push(w); mp[w] = ver; if(que[ver].top() == w) { seg.update(ver, ver+1, w); } } else { int s, t; cin >> s >> t; s--, t--; s = bcc.cmp[s], t = bcc.cmp[t]; int ans = 0; hld.for_each(s, t, [&](int l, int r){ chmax(ans, seg.query(l, r+1)); }); if(ans == 0) { cout << -1 << endl; continue; } cout << ans << endl; int ver = mp[ans]; // cout << que[ver].top() << endl; que[ver].pop(); // cout << que[ver].size() << endl; if(que[ver].size()) { seg.update(ver, ver+1, que[ver].top()); } else { seg.update(ver, ver+1, 0); } } } return 0; }