P4782

【模板】2-SAT 问题

命题 $a$ 命题 $b$ 可以转化为 $\lnot a$ 则 $b$ 以及 $\lnot b$ 则 $a$。

建图跑个 Tarjan,若 $a$ 和 $\lnot a$ 在同一个 SCC 内说明该问题不可能成立。

反之我们需要找可行解。

SCC 缩点之后,显然出度为 $0$ 的点是满足之后条件限制最少的,又因为该问题此时一定有解,所以按照缩点后反图的拓扑序来确定答案一定是一组合法解。

但是直接求拓扑序比较麻烦,我们实际上给 SCC 标过号,根据这个编号我们就能确定一对命题 $a$ 和 $\lnot a$ 的拓扑关系。

显然编号越小越应该优先满足,然后这样确定下来就完事了。

时间复杂度 $O(n)$。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
namespace Ehnaev{
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
return ret*f;
}
inline void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
while(len>=0) putchar(buf[len--]);
}
}using Ehnaev::read;using Ehnaev::write;
inline void writes(ll x) {write(x);putchar(32);}

const ll N=2e6;

ll n,m,tot,cnt,num,top;
ll val[N+5],ver[N+5],nxt[N+5],head[N+5],c[N+5];
ll st[N+5],dfn[N+5],low[N+5];
bool inst[N+5];

inline void Tarjan(ll x) {
dfn[x]=low[x]=++num;st[++top]=x;inst[x]=1;
for(ll i=head[x];i;i=nxt[i]) {
if(!dfn[ver[i]]) {Tarjan(ver[i]);low[x]=min(low[x],low[ver[i]]);}
else {if(inst[ver[i]]) low[x]=min(low[x],dfn[ver[i]]);}
}
if(dfn[x]==low[x]) {
cnt++;
do{inst[st[top]]=0;c[st[top]]=cnt;}while(x!=st[top--]);
}
}

inline void Addedge(ll u,ll v) {
ver[++tot]=v;nxt[tot]=head[u];head[u]=tot;
}

int main() {

n=read();m=read();

for(ll i=1;i<=m;i++) {
ll x,y,p,q;
x=read();p=read();y=read();q=read();
Addedge(x+(1-p)*n,y+q*n);Addedge(y+(1-q)*n,x+p*n);
}

for(ll i=1;i<=n*2;i++) {if(!dfn[i]) Tarjan(i);}

ll flg=0;
for(ll i=1;i<=n;i++) {if(c[i]==c[i+n]) {flg=1;break;}}

if(flg) {printf("IMPOSSIBLE\n");}
else {
printf("POSSIBLE\n");
for(ll i=1;i<=n;i++) {
val[i]=c[i]>c[i+n];writes(val[i]);
}
}

return 0;
}