Let’s go home

Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2756 Accepted Submission(s): 1192

Problem Description
小时候,乡愁是一枚小小的邮票,我在这头,母亲在那头。
—— 余光中

集训是辛苦的,道路是坎坷的,休息还是必须的。经过一段时间的训练,lcy决定让大家回家放松一下,但是训练还是得照常进行,lcy想出了如下回家规定,每一个队(三人一队)或者队长留下或者其余两名队员同时留下;每一对队员,如果队员A留下,则队员B必须回家休息下,或者B留下,A回家。由于今年集训队人数突破往年同期最高记录,管理难度相当大,lcy也不知道自己的决定是否可行,所以这个难题就交给你了,呵呵,好处嘛~,免费**漂流一日。

Input
第一行有两个整数,T和M,1<=T<=1000表示队伍数,1<=M<=5000表示对数。
接下来有T行,每行三个整数,表示一个队的队员编号,第一个队员就是该队队长。
然后有M行,每行两个整数,表示一对队员的编号。
每个队员只属于一个队。队员编号从0开始。

Output
可行输出yes,否则输出no,以EOF为结束。

Sample Input
1 2
0 1 2
0 1
1 2

2 4
0 1 2
3 4 5
0 3
0 4
1 3
1 4

Sample Output
yes
no


一道比较明显的2-SAT,现在我们主要考虑如何建图。

考虑建图:
对于第一种队伍关系:

  1. a走,b,c留
  2. b走,c走,a留
  3. c走,b走,a留
  4. a留,b,c走
  5. b留,c留,a走
  6. c留,b留,a走

对于第二种关系:

  1. a走,b留
  2. b走,a留

然后对于每个队员跑一次tarjan即可,但是这道题并没有说队员是连续的,而是说每个队员有编号,所以我们要用map来离散化每个队员的编号。但是好像这道题数据比较水,不离散化,当成编号连续也能AC

然后检查每个队员,如果这个队员走和这个队员留在同一个强连通分量当中,就输出no,不然输出yes


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=10010,M=100010;
int n,m,dfn[N],col[N],low[N],vis[N],cnt,co,base,flag,idx;
int head[N],nex[M],to[M],tot;
stack<int> st;
unordered_map<int,int> mp;
inline void add(int a,int b){
	to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
inline void init(){
	memset(head,0,sizeof head); memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low); memset(col,0,sizeof col);
	cnt=co=tot=flag=idx=0;	mp.clear();
}
void tarjan(int x){
	dfn[x]=low[x]=++cnt; st.push(x);	vis[x]=1;
	for(int i=head[x];i;i=nex[i]){
		if(!dfn[to[i]]){
			tarjan(to[i]);	low[x]=min(low[x],low[to[i]]);
		}else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
	}
	if(dfn[x]==low[x]){
		co++;
		while(1){
			int u=st.top();	st.pop();	vis[u]=0;
			col[u]=co;	if(u==x)	return ;
		}
	}
}
signed main(){
	while(~scanf("%d %d",&n,&m)){
		init();	base=3*n;
		for(int i=1;i<=n;i++){
			int a,b,c;	scanf("%d %d %d",&a,&b,&c);
			mp[a]=++idx; mp[b]=++idx; mp[c]=++idx;
			add(mp[a]+base,mp[b]);	add(mp[a]+base,mp[c]);
			add(mp[b]+base,mp[a]);	add(mp[b]+base,mp[c]+base);
			add(mp[c]+base,mp[a]);	add(mp[c]+base,mp[b]+base);
			add(mp[a],mp[b]+base);	add(mp[a],mp[c]+base);
			add(mp[b],mp[a]+base);	add(mp[b],mp[c]);
			add(mp[c],mp[a]+base);	add(mp[c],mp[b]);
		}
		while(m--){
			int a,b;	scanf("%d %d",&a,&b);
			add(mp[a],mp[b]+base);	add(mp[b],mp[a]+base);	
		}
		for(int i=1;i<=6*n;i++)	if(!dfn[i])	tarjan(i);
		for(int i=1;i<=base&&!flag;i++)	if(col[i]==col[i+base])	flag++;
		puts(flag?"no":"yes");
	}
	return 0;
}