#include using namespace std; struct TECC { struct Edge { int to, rev; Edge() {} Edge(int t, int r):to(t), rev(r) {} }; int n; vector> G; TECC(int n_) : n(n_), G(n_) {} void add(int u, int v) { G[u].emplace_back(v, int(G[v].size())); G[v].emplace_back(u, int(G[u].size())-1); } pair> tecc_ids() { int now_ord = 0, group_num = 0; vector used, low(n), ord(n, -1), ids(n); used.reserve(n); auto dfs = [&](auto self, int v)->void { low[v] = ord[v] = now_ord++; used.push_back(v); for(Edge &e:G[v]) if(e.rev != -1) { int to = e.to; G[to][e.rev].rev = -1; e.rev = -1; if(ord[to] == -1) { self(self, to); low[v] = min(low[v], low[to]); } else { low[v] = min(low[v], ord[to]); } } if(low[v] == ord[v]) { int u; do { u = used.back(); used.pop_back(); ord[u] = n; ids[u] = group_num; } while(u != v); group_num++; } }; for(int i = 0; i < n; i++) { if(ord[i] == -1) dfs(dfs, i); } for(int &x:ids) { x = group_num - 1 - x; } return {group_num, ids}; } vector> tecc() { pair> ids = tecc_ids(); int group_num = ids.first; vector counts(group_num); for(int x:ids.second) counts[x]++; vector> groups(group_num); for(int i = 0; i < group_num; i++) { groups[i].reserve(counts[i]); } for(int i = 0; i < n; i++) { groups[ids.second[i]].push_back(i); } return groups; } }; struct HLD { using Graph = vector>; using F = function; Graph G; vector parent, heavy, depth, root, ids, sub, type, inv; int _n; HLD() {} HLD(int n):G(n), parent(n, -1), heavy(n, -1), depth(n), root(n, -1), ids(n), _n(n), sub(n, 1), type(n), inv(n) {} void add(int i, int j) { G[i].emplace_back(j); G[j].emplace_back(i); } void init(vector roots = vector(1, 0)) { int group = 0; int pos = 0; for(int rt:roots) { dfs(rt); bfs(rt, group++, pos); } } void dfs(int rt) { stack> st; st.emplace(rt, 0); while(!st.empty()) { int v = st.top().first; int &siz = st.top().second; if(siz < int(G[v].size())) { int u = G[v][siz++]; if(u == parent[v]) continue; parent[u] = v; depth[u] = depth[v]+1; st.emplace(u, 0); } else { st.pop(); int maxSubtree = 0; for(int u:G[v]) { if(u == parent[v]) continue; sub[v] += sub[u]; if(maxSubtree < sub[u]) maxSubtree = sub[u], heavy[v] = u; } } } } void bfs(int rt, int group, int &pos) { queue que({rt}); while(!que.empty()) { int v = que.front(); que.pop(); for(int u = v; u != -1; u = heavy[u]) { type[u] = group; ids[u] = pos++; inv[ids[u]] = u; root[u] = v; for(int w:G[u]) { if(w != parent[u] and w != heavy[u]) que.emplace(w); } } } } //edge = false -> for_each_vertex, edge = true -> for_each_edge void for_each(int u, int v, const F &f, bool edge = false) { assert(type[u] == type[v]); while(true) { if(ids[u] > ids[v]) swap(u, v); if(root[u] == root[v]) { if(edge) { if(u != v) f(ids[u]+1, ids[v]+1); } else f(ids[u], ids[v]+1); break; } f(ids[root[v]], ids[v]+1); v = parent[root[v]]; } } int lca(int u, int v) { while(true) { if(ids[u] > ids[v]) swap(u, v); if(root[u] == root[v]) return u; v = parent[root[v]]; } } int dis(int u, int v) { return depth[u] + depth[v] - (depth[lca(u, v)]<<1); } const int &operator[](int i) const {return ids[i];} }; template struct SegTree { using FX = function; int n, _n; FX fx; const T ex; vector dat; SegTree(int n_, FX fx_, T ex_):fx(fx_), ex(ex_), n(1), _n(n_) { while(n < n_) n <<= 1; dat.assign((n<<1)-1, ex); } SegTree(vector &v, FX fx_, T ex_):fx(fx_), ex(ex_), n(1), _n(int(v.size())) { while(n < _n) n <<= 1; dat.assign((n<<1)-1, ex); copy(v.begin(), v.end(), dat.begin()+n-1); build(); } inline int chld(int k) {return (k<<1)+1;} inline int chrd(int k) {return (k<<1)+2;} void set(int i, T t) {dat[i+n-1] = t;} void build() { for(int k = n-2; k >= 0; k--) dat[k] = fx(dat[chld(k)], dat[chrd(k)]); } void update(int i, T x) { i += n-1; dat[i] = x; while(i) { i = (i-1)>>1; dat[i] = fx(dat[chld(i)], dat[chrd(i)]); } } inline T query(int a, int b) {return query(a, b, 0, 0, n);} T query(int a, int b, int k, int l, int r) { if(r <= a || b <= l) return ex; if(a <= l && r <= b) return dat[k]; T vl = query(a, b, chld(k), l, (l+r)>>1); T vr = query(a, b, chrd(k), (l+r)>>1, r); return fx(vl, vr); } template int max_right(int l, F f) { assert(f(ex)); if(l == _n) return _n; l += n; T now = ex; do { while(~l&1) l >>= 1; if(!f(fx(now, dat[l-1]))) { while(l < n) { l <<= 1; if(f(fx(now, dat[l-1]))) { now = fx(now, dat[l++ - 1]); } } return l-n; } now = fx(now, dat[l++ - 1]); } while((l & -l) != l); return _n; } template int min_left(int r, F f) { assert(f(ex)); if(r == 0) return 0; r += n; T now = ex; do { r--; while(r > 1 and r&1) r >>= 1; if(!f(fx(dat[r-1], now))) { while(r < n) { r = chld(r); if(f(fx(dat[r-1], now))) { now = fx(dat[--r], now); } } return r+1-n; } now = fx(dat[r-1], now); } while((r & -r) != r); return 0; } const T &operator[](int idx) const {return dat[idx+n-1];} }; #undef _GLIBCXX_DEBUG string to_string(const string &s) {return '"' + s + '"';} string to_string(const char *s) {return to_string(string(s));} string to_string(bool b) {return b?"true":"false";} string to_string(vector v) { string res = "{"; for(int i = 0; i < int(v.size()); i++) { if(i) res += ", "; res += to_string(v[i]); } res += "}"; return res; } template string to_string(bitset v) { string res; for(size_t i = 0; i < N; i++) res += char('0' + v[i]); return res; } template string to_string(pair); template string to_string(tuple); template string to_string(tuple); template string to_string(A v) { bool first = true; string res = "{"; for(const auto &x:v) { if(!first) res += ", "; first = false; res += to_string(x); } res += "}"; return res; } template string to_string(pair p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; } template string to_string(tuple t) { return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " + to_string(get<2>(t)) + ")"; } template string to_string(tuple t) { return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " + to_string(get<2>(t)) + ", " + to_string(get<3>(t)) + ")"; } void debug_out() {cerr << endl;} template void debug_out(Head H, Tail... T) { cerr << ' ' << to_string(H); debug_out(T...); } #ifdef LOCAL #define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__) #else #define debug(...) 822 #endif int main() { int n, m, q; cin >> n >> m >> q; TECC tecc(n); vector> edges(m); for(int i = 0; i < m; i++) { int a, b; cin >> a >> b; tecc.add(--a, --b); edges[i] = {a, b}; } auto [gn, blg] = tecc.tecc_ids(); debug(blg); debug(gn); HLD hld(gn); for(int i = 0; i < m; i++) { auto [u, v] = edges[i]; if(blg[u] == blg[v]) continue; hld.add(blg[u], blg[v]); } hld.init(); debug(hld.ids); debug(hld.root); debug(hld.parent); SegTree> seg(gn, [](const pair &a, const pair &b) {return max(a, b);}, make_pair(-1, -1)); auto cor = [&](int i) {return hld[blg[i]];}; vector> souv(gn); while(q--) { int type; cin >> type; if(type == 1) { int u, w; cin >> u >> w; u = cor(u-1); debug(u); if(souv[u].empty() or souv[u].top() < w) seg.update(u, make_pair(w, u)); souv[u].emplace(w); } else { int s, t; cin >> s >> t; pair p = make_pair(-1, -1); hld.for_each(blg[s-1], blg[t-1], [&](int i, int j)->void {p = max(p, seg.query(i, j));}); debug(p); if(p.first == -1) { cout << "-1\n"; } else { cout << p.first << '\n'; int z = p.second; souv[z].pop(); if(souv[z].empty()) seg.update(z, make_pair(-1, -1)); else seg.update(z, make_pair(souv[z].top(), z)); } } } }