#include using namespace std; // 0-indexed template struct SegmentTree { // a,b,c: T, e:T(unit) // abc = (ab)c = a(bc) // ae = ea = a typedef function F; int n; F f; T unit; vector dat; SegmentTree(){}; SegmentTree(int newn, F f, T t) : f(f), unit(t) { init(newn); } SegmentTree(const vector &v, F f, T t) : f(f), unit(t) { int _n = v.size(); init(v.size()); for (int i = 0; i < _n; ++i) dat[n + i] = v[i]; for (int i = n - 1; i; --i) dat[i] = f(dat[i << 1], dat[(i << 1) | 1]); } void init(int newn) { n = 1; while (n < newn) n <<= 1; dat.assign(n << 1, unit); } // "go up" process void update(int k, T newdata) { dat[k += n] = newdata; while (k >>= 1) { dat[k] = f(dat[(k << 1) | 0], dat[(k << 1) | 1]); } } // [a,b) T query(int a, int b) { T vl = unit, vr = unit; for (int l = a + n, r = b + n; l < r; l >>= 1, r >>= 1) { if (l & 1) vl = f(vl, dat[l++]); if (r & 1) vr = f(dat[--r], vr); } return f(vl, vr); } }; struct HeavyLightDecomposition { int root; vector> g; vector sz, par, dep, in, out, head; HeavyLightDecomposition(int n = 1, int _root = 0) : root(_root), g(n), sz(n), par(n), dep(n), in(n), out(n), head(n) {} HeavyLightDecomposition(const vector> &_g, const int _root = 0) : root(_root), g(_g), sz(_g.size()), par(_g.size()), dep(_g.size()), in(_g.size()), out(_g.size()), head(_g.size()) { build(); } void add(int a, int b) { g[a].push_back(b); g[b].push_back(a); } void build() { dfs_sz(root, -1, 0); int t = 0; dfs_hld(root, -1, t); } void dfs_sz(int now, int bf, int d) { dep[now] = d; par[now] = bf; sz[now] = 1; if (g[now].size() && g[now][0] == bf) swap(g[now][0], g[now].back()); for (auto &to : g[now]) { if (to == bf) continue; dfs_sz(to, now, d + 1); sz[now] += sz[to]; if (sz[g[now][0]] < sz[to]) swap(g[now][0], to); } } void dfs_hld(int now, int bf, int &t) { in[now] = t++; for (auto &to : g[now]) { if (to == bf) continue; head[to] = (g[now][0] == to ? head[now] : to); dfs_hld(to, now, t); } out[now] = t; } int lca(int x, int y) { for (;; y = par[head[y]]) { if (in[x] > in[y]) swap(x, y); if (head[x] == head[y]) return x; } } int chil(int x, int y) { return dep[x] < dep[y] ? y : x; } //[l,r) template void for_each(int x, int y, const F &f) { for (;; y = par[head[y]]) { if (in[x] > in[y]) swap(x, y); f(max(in[head[y]], in[x]), in[y] + 1); if (head[x] == head[y]) return; } } //[l,r) template void for_eachedge(int x, int y, const F &f) { while (1) { if (in[x] > in[y]) swap(x, y); if (head[x] != head[y]) { f(in[head[y]], in[y] + 1); y = par[head[y]]; } else { if (x != y) f(in[x] + 1, in[y] + 1); break; } } } template void update(int node, T x, const F &f) { f(in[node], x); f(out[node], -x); // laze pattern // f(in[node], out[node], x); } }; // TwoEdgeConnectedComponents + LowLink struct TwoEdgeConnectedComponents { int n; vector> g; vector ord, low, articulation, id; vector used; using P = pair; vector

bridge; TwoEdgeConnectedComponents(int _n = 1) : n(_n), g(n) {} TwoEdgeConnectedComponents(vector> &_g) : n(_g.size()), g(_g) { lowlinkbuild(); } bool add(int from, int to) { g[from].push_back(to); g[to].push_back(from); return 1; } void lowlinkbuild() { ord.assign(n, -1); low.assign(n, -1); int k = 0; for (int i = 0; i < n; ++i) if (ord[i] < 0) lowlinkdfs(i, -1, k); } void lowlinkdfs(int now, int par, int &k) { ord[now] = low[now] = k++; bool ch = 0; // articulation int cnt = 0; for (auto &to : g[now]) if (ord[to] < 0) { ++cnt; lowlinkdfs(to, now, k); low[now] = min(low[now], low[to]); ch |= ~par && low[to] >= ord[now]; // articulation if (ord[now] < low[to]) bridge.emplace_back(min(now, to), max(now, to)); // bridge } else if (to != par) low[now] = min(low[now], ord[to]); ch |= par == -1 && cnt > 1; // articulation if (ch) articulation.push_back(now); // articulation } vector> build() { id.assign(n, -1); int k = 0; for (int i = 0; i < n; ++i) if (id[i] < 0) dfs(i, -1, k); vector> res(k); for (auto &e : bridge) { int x = id[e.first], y = id[e.second]; res[x].push_back(y); res[y].push_back(x); } return res; } void dfs(int now, int par, int &k) { if (~par && ord[par] >= low[now]) id[now] = id[par]; else id[now] = k++; for (auto &to : g[now]) if (id[to] < 0) dfs(to, now, k); } inline int operator[](const int &k) { return (id.at(k)); } }; using P = pair; long long n, m, q; TwoEdgeConnectedComponents tecc; SegmentTree

seg; HeavyLightDecomposition hld; vector> g; vector> lst; int main() { cin >> n >> m >> q; g.resize(n); for (int i = 0; i < m; ++i) { int a, b; cin >> a >> b; g[--a].push_back(--b); g[b].push_back(a); } tecc = TwoEdgeConnectedComponents(g); hld = HeavyLightDecomposition(tecc.build()); lst.resize(n); auto f = [](P l, P r) { return max(l, r); }; seg = SegmentTree

(n, f, P(-1, -1)); for (int i = 0; i < q; ++i) { int a, b, c; cin >> a >> b >> c; if (a == 1) { int x = tecc[--b]; lst[x].push(c); seg.update(x, P(lst[x].top(), x)); } else { int x = tecc[--b], y = tecc[--c]; P res(-1, -1); auto func = [&](int l, int r) { res = max(res, seg.query(l, r)); }; hld.for_each(x, y, func); cout << res.first << endl; if (res.first >= 0) { x = res.second; lst[x].pop(); long long num = -1; if (lst[x].size()) num = lst[x].top(); seg.update(x, P(num, x)); } } } return 0; }