int stk[N],vis[N],low[N],link[N],mark[N];
int top,index,id,du[N];//记录入度数
int pre[N],cnt,g[N];// g 用来记录topsort后的结果
int g1[N]; //用来记录缩点后的每一个点所含的点
void dfs(int s)
{
mark[s]=;
vis[s]=index++;
low[s]=vis[s];
stk[top++]=s;
for(int p=pre[s];p!=-;p=edge[p].next)
{
int v=edge[p].to;
if(mark[v]==) dfs(v);
if(mark[v]==) low[s]=min(low[s],low[v]);
}
if(low[s]==vis[s])
{
int tmp;
id++;
do
{
tmp=stk[top-];
link[tmp]=id;
mark[tmp]=-;
}while(stk[--top]!=s);
}
}
void add_edge(int u,int v)
{
edge[cnt].from=u;
edge[cnt].to=v;
edge[cnt].next=pre[u];
pre[u]=cnt++;
}
void topsort()
{
memset(mark,,sizeof(mark));
top=;
int tcnt=;
for(int i=;i<=id;i++)
if(du[i]==)
{
mark[i]=;
stk[top++]=i;//把这个节点入栈
g[tcnt++]=i;
}
while(top!=)
{
int cur=stk[--top];
for(int p=pre[cur];p!=-;p=edge[p].next)
{
int v=edge[p].to;
if(mark[v]==) continue;
du[v]--;
if(du[v]==)
{
mark[v]=;
stk[top++]=v;
g[tcnt++]=v;
}
}
}
}
void dfs1(int s) //将所有不可能的情况标记
{
mark[s]=-;
for(int p=pre[s];p!=-;p=edge[p].next)
{
int v=edge[p].to;
dfs1(v);
}
}
void sat2(int sn) //top 表示传入的点数。 其中要保证标号从0开始而且0和1是一组
{
top=index=id=;
memset(mark,,sizeof(mark));
for(int i=;i<sn;i++)
if(mark[i]==)
dfs(i);
int flag=;
for(int i=;i<sn;i+=)
{
if(link[i]==link[i+])
{
flag=;
break;
}
}
if(flag)
{
/* 当不可行的时候输出 */
printf("bad luck\n");
}
else
{
/* 可行的时候输出 */
printf("YES\n");
int tcnt=cnt;
memset(g1,,sizeof(g1));
cnt=;
memset(pre,-,sizeof(pre));
for(int i=;i<sn;i++)
{
g1[ link[i] ]=i;
}
memset(du,,sizeof(du));
for(int i=;i<tcnt;i++)
{
int x=edge[i].from;
int y=edge[i].to;
if(link[x] != link[y])
{
add_edge(link[y],link[x]);//建逆图
du[ link[x] ]++;
}
}
topsort();
memset(mark,,sizeof(mark));
for(int i=;i<id;i++)
{
if(mark[ g[i] ]!=-)//表示这个点可以选
{
mark[ g[i] ]=;
int key=g1[ g[i] ];
key=key^;
key=link[key];
dfs1(key);
}
}
/* print mark[ link[i] ]==1 的表示可选的 */
}
}