#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector") #pragma GCC target("sse3") #include "bits/stdc++.h" using namespace std; using ll = long long; using Vi = vector; using Pii = pair; #define pb push_back #define mp make_pair #define x first #define y second #define rep(i,b,e) for (int i=(b); i < (e); i++) #define each(a,x) for(auto& a : (x)) #define all(x) (x).begin(), (x).end() #define sz(x) int((x).size()) struct Query { int type, v1, v2, lvl; int ans{100}; }; struct Inter { int begin, end; Pii edge; }; int n, q, len; vector queries; vector inters[10]; vector> tree; vector gRestore; Vi par; int gLvl; int getPar(int v) { while (par[v] != -1) v = par[v]; return v; } void add(int vBegin, int vEnd, Pii val, int i, int beg, int end) { if (vEnd <= beg || end <= vBegin) return; if (vBegin <= beg && end <= vEnd) { tree[i].pb(val); return; } int m = (beg+end)/2; add(vBegin, vEnd, val, i*2, beg, m); add(vBegin, vEnd, val, i*2+1, m, end); } void dfs(int i, int beg, int end) { if (beg >= sz(queries)) return; Vi& restore = gRestore[i]; restore.clear(); each(e, tree[i]) { int p1 = getPar(e.x), p2 = getPar(e.y); if (p1 != p2) { if (rand() % 2) swap(p1, p2); restore.pb(p1); par[p1] = p2; } } if (i < len) { int m = (beg+end)/2; dfs(i*2, beg, m); dfs(i*2+1, m, end); } else { int ind = i-len; if (ind < sz(queries)) { auto& e = queries[ind]; if (e.type == 2) { int p1 = getPar(e.v1), p2 = getPar(e.v2); if (p1 == p2) { e.ans = min(e.ans, gLvl); } } } } each(v, restore) par[v] = -1; } void solve(int lvl) { gLvl = lvl; each(e, inters[lvl]) { add(e.begin, e.end, e.edge, 1, 0, len); } dfs(1, 0, len); } int main() { cin.sync_with_stdio(0); cin.tie(0); cout << fixed << setprecision(18); cin >> n >> q; queries.resize(q); each(e, queries) { cin >> e.type >> e.v1 >> e.v2; if (e.type == 0) cin >> e.lvl; if (e.v1 > e.v2) swap(e.v1, e.v2); } len = 1; while (len < q) len *= 2; map mip; rep(i, 0, q) { auto& e = queries[i]; if (e.type == 0) { mip[mp(e.v1, e.v2)] = i; } else if (e.type == 1) { int j = mip[mp(e.v1, e.v2)]; inters[queries[j].lvl].pb({ j, i, mp(e.v1, e.v2) }); mip.erase(mp(e.v1, e.v2)); } } for (auto p : mip) { int j = p.y, i = len; inters[queries[j].lvl].pb({ j, i, p.x }); } par.resize(n, -1); tree.resize(len*2); gRestore.resize(len*2); rep(i, 0, 10) solve(i); each(e, queries) { if (e.type != 2) continue; cout << (e.ans < 20 ? e.ans : -1) << '\n'; } return 0; }