#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=10005;
struct lct
{
lct *fa,*son[2];
int rev;
void pushdown() //把延迟更新的标记清除掉
{
if(!rev) return;
swap(son[0],son[1]); //翻转,交换左右儿子
son[0]->rev^=1; son[1]->rev^=1;
rev=0;
}
};
struct LCT
{
lct data[maxn];
lct *null;
void init(int Size=maxn-1) //初始化
{
null=data; //null指向首元素
for(int i=0;i<=Size;i++)
data[i].son[0]=data[i].son[1]=data[i].fa=null;
}
bool Same(lct* x,lct* &y) //判断x和x的父亲是否在同一树里
{
return (y=x->fa)!=null&&(y->son[0]==x||y->son[1]==x);
}
void Rotate(lct* x,int d) //翻转
{
lct* y=x->fa; //x的父亲
y->son[d^1]=x->son[d];
if(x->son[d]!=null) x->son[d]->fa=y; //x的子节点的父亲指向y
x->fa=y->fa; //连接
if(y->fa->son[0]==y) x->fa->son[0]=x;
else if(y->fa->son[1]==y) x->fa->son[1]=x;
x->son[d]=y;
y->fa=x;
}
void Splay(lct* x)
{
x->pushdown(); //清除标记
lct* y;
while(Same(x,y)) //没有到树的最顶点
{
y->pushdown();
x->pushdown();
Rotate(x,y->son[0]==x); //翻转
}
}
lct* Access(lct* u) //打通路径
{
lct *v=null;
for(;u!=null;u=u->fa)
{
Splay(u);
u->son[1]=v;
v=u;
}
return v;
}
lct* GetRoot(lct* x) //得到根
{
for(x=Access(x);x->pushdown(),x->son[0]!=null;x=x->son[0]);
return x;
}
void MakeRoot(lct* x) //使x成为根
{
Access(x)->rev^=1;
Splay(x);
}
void Link(lct* x,lct* y) //连接两个点
{
MakeRoot(x);
x->fa=y;
Access(x);
}
void Cut(lct* x,lct* y) //断开两个点
{
MakeRoot(x);
Access(y);
Splay(y);
y->son[0]->fa=null;
y->son[0]=null;
}
}A;
int N,M;
int main()
{
scanf("%d%d",&N,&M);
A.init(N);
int x,y;
char S[10];
while(M--)
{
scanf("%s%d%d",S,&x,&y);
if(S[0]==‘Q‘)
{
lct *a=A.GetRoot(A.data+x);
lct *b=A.GetRoot(A.data+y);
if(a!=A.null&&a==b) printf("Yes\n");
else printf("No\n");
}
else if(S[0]==‘D‘) A.Cut(A.data+x,A.data+y);
else A.Link(A.data+x,A.data+y);
}
return 0;
}