#include
using namespace std;
typedef pair <int, int> epr;
typedef set
struct seg { int s, z, l, r; seg *ls, *rs; }; struct edge { int t; edge *next; }; struct oper { int t, u, v, s; };
const int maxn = 30009; const int maxq = 40009; const int maxe = 100009;
int n, m, q, r[maxn]; int fa[maxn], d[maxn], sz[maxn], tc, fc[maxn], ch[maxn], cl[maxn]; seg sbuf_arr[maxn « 2], *sbuf(sbuf_arr), *rt[maxn]; oper o[maxq]; erbt re; edge ebuf_arr[maxn « 1], *ebuf(ebuf_arr), *head[maxn];
#define midp(p) ((p->l+p->r)»1) inline seg* sgtBuild(int l, int r) { seg p(sbuf ++); p-> l = l, p-> r = r; p-> s = r - l; p-> z = 0; if (l + 1 < r) { p-> ls = sgtBuild(l, midp(p)); p-> rs = sgtBuild(midp(p), r); } return p; } inline void sgtChg(seg p, int l, int r) { if (p-> l == l && p-> r == r) p-> z = 1, p-> s = 0; else if (p-> z) return; else { if (r <= midp(p)) sgtChg(p-> ls, l, r); else if (l >= midp(p)) sgtChg(p-> rs, l, r); else sgtChg(p-> ls, l, midp(p)), sgtChg(p-> rs, midp(p), r); p-> s = p-> ls-> s + p-> rs-> s; } } inline int sgtQry(seg* p, int l, int r) { if (p-> l == l && p-> r == r) return p-> s; else if (p-> z) return 0; else if (r <= midp(p)) return sgtQry(p-> ls, l, r); else if (l >= midp(p)) return sgtQry(p-> rs, l, r); else return sgtQry(p-> ls, l, midp(p)) + sgtQry(p-> rs, midp(p), r); }
#define cpos(x) (d[x]-d[ch[fc[x]]]) void ersBridge(int u, int v) { while (fc[u] ^ fc[v]) if (d[ch[fc[u]]] > d[ch[fc[v]]]) { sgtChg(rt[fc[u]], 0, cpos(u) + 1); u = fa[ch[fc[u]]]; } else { sgtChg(rt[fc[v]], 0, cpos(v) + 1); v = fa[ch[fc[v]]]; } if (d[u] < d[v]) sgtChg(rt[fc[u]], cpos(u) + 1, cpos(v) + 1); else if (d[v] < d[u]) sgtChg(rt[fc[v]], cpos(v) + 1, cpos(u) + 1); }
int getRoot(int x) { register int p, q; for (p = r[x]; p ^ r[p]; p = r[p]); for (; x ^ p; q = r[x], r[x] = p, x = q); return x; }
inline void addEdge(int u, int v) { ebuf-> t = v; ebuf-> next = head[u]; head[u] = ebuf ++; }
void buildTree() { for (int i = 1; i <= n; ++ i) r[i] = i; static epr rme[maxe]; int tre(0); for (erbt :: iterator i = re. begin(); i != re. end(); ++ i) { int u(i-> first), v(i-> second); if (getRoot(u) != getRoot(v)) { addEdge(u, v); addEdge(v, u); r[getRoot(u)] = getRoot(v); } else rme[tre ++] = i; } static int q[maxn]; int hd(0), tl(1); memset(d, 0, sizeof(d)); d[q[0] = 1] = 1; while (hd < tl) { int p(q[hd ++]); for (edge e = head[p]; e; e = e-> next) if (!d[e-> t]) { fa[e-> t] = p; d[e-> t] = d[p] + 1; q[tl ++] = e-> t; } } tc = 0; for (int i = tl - 1; i >= 0; – i) { int p(q[i]), z(-1); sz[p] = 1; for (edge* e = head[p]; e; e = e-> next) if (e-> t != fa[p]) { sz[p] += sz[e-> t]; if (z == -1 || sz[e-> t] > sz[z]) z = e-> t; } if (z == -1) cl[fc[p] = ++ tc] = 1; else ++ cl[fc[p] = fc[z]]; ch[fc[p]] = p; } for (int i = 1; i <= tc; ++ i) rt[i] = sgtBuild(0, cl[i]); for (int i = 0; i < tre; ++ i) ersBridge(rme[i]. first, rme[i]. second); }
int main() { #ifndef ONLINE_JUDGE freopen(".in", “r”, stdin); #endif
scanf("%d%d", &n, &m);
for (int i = 0; i < m; ++ i) {
int u, v;
scanf("%d%d", &u, &v);
if (u > v)
swap(u, v);
re. insert(epr(u, v));
}
for (q = 0; 1; ++ q) {
int opt;
scanf("%d", &opt);
if (opt == -1)
break;
o[q]. t = opt;
scanf("%d%d", &o[q]. u, &o[q]. v);
if (o[q]. u > o[q]. v)
swap(o[q]. u, o[q]. v);
if (opt == 0)
re. erase(epr(o[q]. u, o[q]. v));
}
buildTree();
for (int i = q - 1; i >= 0; -- i)
if (o[i]. t == 0) {
ersBridge(o[i]. u, o[i]. v);
}
else if (o[i]. t == 1) {
o[i]. s = 0;
int u(o[i]. u), v(o[i]. v);
while (fc[u] ^ fc[v])
if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
o[i]. s += sgtQry(rt[fc[u]], 0, cpos(u) + 1);
u = fa[ch[fc[u]]];
}
else {
o[i]. s += sgtQry(rt[fc[v]], 0, cpos(v) + 1);
v = fa[ch[fc[v]]];
}
if (d[u] < d[v])
o[i]. s += sgtQry(rt[fc[u]], cpos(u) + 1, cpos(v) + 1);
else if (d[v] < d[u])
o[i]. s += sgtQry(rt[fc[v]], cpos(v) + 1, cpos(u) + 1);
}
for (int i = 0; i < q; ++ i)
if (o[i]. t == 1)
printf("%d\n", o[i]. s);
}