每个元素只有两种可能的取值,所以是2-SAT的模型.
我们建立$n+n$个点,$x\in [1..n]$表示$x$取$0$,$x\in [n+1..n+n]$表示$x$取$1$
考虑将所给的关系转化为有向边.
- $u\ and\ v=1$:$u,v$都必须是1.为了让他们都是1,我们需要让他们为0时出现矛盾,也就是加边$(u,u+n),(v,v+n)$
- $u\ and\ v=0$:如果$u=1$那么$v=0$,加边$(u+n,v)$.同理,加边$(v+n,u)$
- $u\ or\ v=1$:如果$u=0$那么$v=1$,加边$(u,v+n)$.同理,加边$(v,u+n)$
- $u\ or\ v=0$:$u,v$都必须是0.为了让他们都是0,我们需要让他们为1时出现矛盾,也就是加边$(u+n,u),(v+n,v)$
- $u\ xor\ v=0$:$u=v$,所以加边$(u,v),(v,u),(u+n,v+n),(v+n,u+n)$
- $u\ xor\ v=1$:$u\neq v$,所以加边$(u,v+n),(v,u+n),(u+n,v),(v+n,u)$
图建完之后,跑一遍tarjan求出所有SCC,若出现矛盾(即存在$scc[x]==scc[x+n]$)就不存在解.否则存在.
时间复杂度$O(n+m)$.注意边数点数开足够.
/**********/
#define MAXN 2011
#define MAXM 1000011
struct Edge
{
ll v,nxt;
}e[MAXM<<2|1];
ll cnt=0,last[MAXN];
void adde(ll u,ll v)
{
e[++cnt].v=v;
e[cnt].nxt=last[u],last[u]=cnt;
}
char a[5];
ll dfn[MAXN],low[MAXN],cur=0,scc[MAXN],scnt;
ll s[MAXN],top=0;
bool ins[MAXN];
void tarjan(ll u)
{
dfn[u]=low[u]=++cur;
s[++top]=u;ins[u]=1;
for(ll i=last[u];i;i=e[i].nxt)
{
ll v=e[i].v;
if(!dfn[v])
{
tarjan(v);
umin(low[u],low[v]);
}
else if(ins[v])umin(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
++scnt;
while(s[top]!=u)
{
scc[s[top]]=scnt;
ins[s[top]]=0;
--top;
}
scc[s[top--]]=scnt;
ins[u]=0;
}
}
int main()
{
ll n=read(),m=read();
for(ll i=1;i<=m;++i)
{
ll u=read()+1,v=read()+1,c=read();//[1..n]:0 [n+1..2n]:1
scanf("%s",a);
char op=a[0];
if(op=='A')//f[u] and f[v]
{
if(c)adde(u,u+n),adde(v,v+n);//==1
else adde(u+n,v),adde(v+n,u);//
}
else if(op=='O')
{
if(c)adde(u,v+n),adde(v,u+n);
else adde(u+n,u),adde(v+n,v);
}
else//xor
{
if(c)adde(u,v+n),adde(u+n,v),adde(v,u+n),adde(v+n,u);
else adde(u,v),adde(v,u),adde(u+n,v+n),adde(v+n,u+n);
}
}
for(ll i=1;i<=n+n;++i)
if(!dfn[i])tarjan(i);
for(ll i=1;i<=n;++i)
if(scc[i]==scc[i+n])
{
puts("NO");
return 0;
}
puts("YES");
return 0;
}