#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
const int MaxL = 16, N = 5005;
char buf[1 << 20], *p1, *p2;
#define GC (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? 0 : *p1 ++)
inline int _R() {
	int d = 0; bool ty = 1; char t;
	while (t = GC, (t < '0' || t > '9') && t != '-');
	t == '-' ? (ty = 0) : (d = t - '0');
	while (t = GC, t >= '0' && t <= '9') d = (d << 3) + (d << 1) + t - '0';
	return ty ? d : -d;
}
inline int RD() {
	static int seed = 20010916;
	return seed =( (seed ^ 21323123)* 998244353 + 1234321237) & 0x7fffffff;
}
int n, m;
struct Graph {	
	set<int> mt[N];
	void add(int x, int y) {
		mt[x].insert(y);
		mt[y].insert(x);
	}
	
	void del(int x, int y) {
		mt[x].erase(y);
		mt[y].erase(x);
	}
	bool find(int x, int y) {
		return mt[x].count(y);
	}
	bool empty(int x) { return mt[x].empty(); }
} G[MaxL];
struct Node {
	Node *Son[2], *fa;
	bool hav;
	int pid, tid, sz, w;
} pool[10000000], *bin[10000000], *null;
int tl;
void ninit() {
	null = pool;
	null -> Son[0] = null -> Son[1] = null -> fa = null;
	for (int i = 1; i < N * MaxL; i ++) bin[i] = pool + i;
}
struct ETT {
	Graph *G;
	set<int> e[N];
	map<int, int> mt[N];
	Node *End[2000005], *id[N]; int tote;
	Node* newnode(int id, int tid) {
		Node *x = bin[++ tl];
		x -> pid = id;
		x -> tid = tid;
		x -> w = RD();
		x -> hav = id && !G -> empty(id);
		x -> sz = 1;
		x -> Son[0] = x -> Son[1] = x -> fa = null;
		return x;
	}
	void delnode(Node *x) {
		bin[tl --] = x;
	}
	void pushup(Node *x) {
		x -> hav = (x -> pid && !G -> empty(x -> pid)) || x -> Son[0] -> hav || x -> Son[1] -> hav;
		x -> sz = x -> Son[0] -> sz + x -> Son[1] -> sz + 1;
	}
	void split_up(Node *x, Node *&l, Node *&r) {
		if (x -> fa == null) return;
		Node *y = x -> fa; x -> fa = null;
		if (y -> Son[0] == x) {
			y -> Son[0] = r;
			r -> fa = y;
			pushup(y);
			r = y;
		}
		else {
			y -> Son[1] = l;
			l -> fa = y;
			pushup(y);
			l = y;
		}
		split_up(y, l, r);
	}
	void split(Node *x, Node *&l, Node *&r) {
		l = x -> Son[0], r = x -> Son[1];
		x -> Son[0] = x -> Son[1] = l -> fa = r -> fa = null;
		pushup(x);
		split_up(x, l, r);
	}
	Node* merge(Node *l, Node *r) {
		if (l == null || r == null) return l == null ? r : l;
		if (RD()&16) {
			l -> Son[1] = merge(l -> Son[1], r);
			l -> Son[1] -> fa = l;
			pushup(l);
			return l;
		}
		else {
			r -> Son[0] = merge(l, r -> Son[0]);
			r -> Son[0] -> fa = r;
			pushup(r);
			return r;
		}
	}
	void makeroot(Node *&x) {
		if (x == null) return;
		Node *l, *r;
		split(x, l, r);
		x = merge(merge(x, r), l);
	}
	Node* findrt(Node *x) {
		while (x -> fa != null) x = x -> fa;
		while (x -> Son[0] != null) x = x -> Son[0];
		return x;
	}
	Node *findrt(int x) {
		return findrt(id[x]);
	}
	void add(int u, int v, bool lev) {
		Node *x = id[u], *y = id[v];
		if (x != null && y != null && findrt(x) == findrt(y)) {
			pushup(x), pushup(y);
			while (x -> fa != null) x = x -> fa, pushup(x);
			while (y -> fa != null) y = y -> fa, pushup(y);
			return;
		}
		makeroot(x), makeroot(y);
		End[++ tote] = newnode(x == null ? u : 0, u), mt[u][v] = tote;
		End[++ tote] = newnode(y == null ? v : 0, v), mt[v][u] = tote;
		if (lev) e[u].insert(v), e[v].insert(u);
		merge(merge(merge(End[tote - 1], y), End[tote]), x);
		if (x == null) id[u] = End[tote - 1];
		if (y == null) id[v] = End[tote];
	}
	void getid(int x) {
		if (mt[x].empty()) { id[x] = null; return; }
		id[x] = End[mt[x].begin() -> second];
		Node *l, *r;
		split(id[x], l, r);
		id[x] -> pid = x; pushup(id[x]);
		merge(merge(id[x], r), l);
	}
	int del(int u, int v) {
		int eid = mt[u][v];
		mt[u].erase(v), mt[v].erase(u);
		Node *x = End[eid], *y = End[eid ^ 1], *l, *r;
		split(x, l, r);
		merge(r, l);
		split(y, l, r);
		int t0 = l -> sz,
			t1 = r -> sz;
		if (x -> pid) getid(u);
		if (y -> pid) getid(v);
		delnode(x), delnode(y);
		return t1 < t0 ? u : v;
	}
	
	void init(int x) {
		tote = 1;
		fill(id, id + n + 1, null);
		G = :: G + x;
	}
	void _print(Node *p) {
		if (p -> Son[0] != null) _print(p -> Son[0]);
		printf("%d ", p -> tid);
		if (p -> Son[1] != null) _print(p -> Son[1]);
	}
	void print(int x) {
		Node *p = id[x];
		if (p == null) return;
		makeroot(p);
		_print(p);
		puts("");
	}
} T[MaxL];
namespace D_Graph {
	void addlevel(int level, Node *x) {
		if (x == null || !x -> hav) return;
		if (x -> pid) {
			int u = x -> pid;
			for (auto v : T[level].e[u]) if (u < v) {
				G[level].del(u, v);
				G[level + 1].add(u, v);
				T[level + 1].add(u, v, 1);
			}
			T[level].e[u].clear();
		}
		addlevel(level, x -> Son[0]);
		addlevel(level, x -> Son[1]);
		T[level].pushup(x);
	}
	Node *xrt;
	int X, Y;
	bool findin_G(int level, int x) {
		while (!G[level].empty(x)) {
			int u = *G[level].mt[x].begin();
			if (T[level].findrt(u) != xrt) {
				X = x, Y = u;
				return 1;
			}
			G[level].del(x, u);
			G[level + 1].add(x, u);
			T[level + 1].add(x, u, 0);
		}
		return 0;
	}
	bool findin_T(int level, Node *x) {
		if (x == null || !x -> hav) return 0;
		if (x -> pid) if (findin_G(level, x -> pid)) return 1;
		if (findin_T(level, x -> Son[0])) return 1;
		if (findin_T(level, x -> Son[1])) return 1;
		x -> hav = 0;
		return 0;
	}
	
	void find_replacement(int level, int x) {
		Node *p = T[level].id[x];
		xrt = p;
		if (p == null) findin_G(level, x);
		else T[level].makeroot(p), addlevel(level, p), findin_T(level, p);
	}
	void add(int x, int y) {
		G[0].add(x, y);
		T[0].add(x, y, 1);
	}
	void del(int x, int y) {
		for (int i = MaxL - 1; i >= 0; i --) if (G[i].find(x, y)) {
			G[i].del(x, y);
			if (!T[i].mt[x].count(y)) return;
			T[i].e[x].erase(y);
			T[i].e[y].erase(x);
			X = Y = 0;
			for (int j = i; j >= 0; j --) {
				
					
					
				
				int t = T[j].del(x, y);
				if (!X) {
					find_replacement(j, t);
					if (X) T[j].add(X, Y, 1);
				}
				else T[j].add(X, Y, 0);
			}
			return;
		}
	}
	bool isconnected(int x, int y) {
		return T[0].id[x] != null && T[0].id[y] != null && T[0].findrt(x) == T[0].findrt(y);
	}
}
int main() {
	
	int i, opt, x, y, ans = 0;
	n = _R(), m = _R();
	ninit();
	for (i = 0; i < MaxL; i ++) T[i].init(i);
	for (i = 1; i <= m; i ++) {
		opt = _R(), x = _R() ^ ans, y = _R() ^ ans;
		assert(x && y);
		if (opt == 0) D_Graph :: add(x, y);
		else if (opt == 1) D_Graph :: del(x, y);
		else {
			ans = D_Graph :: isconnected(x, y);
			puts(ans ? "Y" : "N");
			ans = ans ? x : y;
		}
		
		
	}
}