# Exploration

Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1349    Accepted Submission(s): 363

Problem Description
Miceren likes exploration and he found a huge labyrinth underground!

This labyrinth has N caves and some tunnels connecting some pairs of caves.

There are two types of tunnel, one type of them can be passed in only one direction and the other can be passed in two directions. Tunnels will collapse immediately after Miceren passing them.

Now, Miceren wants to choose a cave as his start point and visit at least one other cave, finally get back to start point.

As his friend, you must help him to determine whether a start point satisfing his request exists.

Input
The first line contains a single integer T, indicating the number of test cases.

Each test case begins with three integers N, M1, M2, indicating the number of caves, the number of undirectional tunnels, the number of directional tunnels.

The next M1 lines contain the details of the undirectional tunnels. Each line contains two integers u, v meaning that there is a undirectional tunnel between u, v. (u  v)

The next M2 lines contain the details of the directional tunnels. Each line contains integers u, v meaning that there is a directional tunnel from u to v. (u  v)

1  N,M1,M2  1000000.

There may be some tunnels connect the same pair of caves.

The ratio of test cases with N > 1000 is less than 5%.

Output
For each test queries, print the answer. If Miceren can do that, output "YES", otherwise "NO".

Sample Input
2 5 2 1 1 2 1 2 4 5 4 2 2 1 2 2 3 4 3 4 1

Sample Output
YES NO
Hint
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.

Source

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=1e6+10,M=4e6+10,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n,m1,m2,x,y;
int first[N],id;
int w[M],c[M],nxt[M];
int f[N];
bool e[N],vis[N],flag;
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void ins(int x,int y)
{
++id;
w[id]=y;
nxt[id]=first[x];
first[x]=id;
}
bool tarjan(int x)
{
vis[x]=1;
e[x]=1;
for(int z=first[x];z;z=nxt[z])
{
int y=w[z];
if(vis[y]==0&&tarjan(y))return 1;
if(e[y])return 1;
}
e[x]=0;
return 0;
}
int main()
{
scanf("%d",&casenum);
for(casei=1;casei<=casenum;++casei)
{
scanf("%d%d%d",&n,&m1,&m2);
for(int i=1;i<=n;i++)f[i]=i;
flag=0;
for(int i=1;i<=m1;i++)
{
scanf("%d%d",&x,&y);
x=find(x);
y=find(y);
if(x==y)flag=1;
else f[y]=x;
}
if(flag)
{
for(int i=1;i<=m2;i++)scanf("%*d%*d");
printf("YES\n");
continue;
}
for(int i=1;i<=n;i++)
{
f[i]=find(i);
first[i]=0;
vis[i]=0;
e[i]=0;
}
for(int i=1;i<=m2;i++)
{
scanf("%d%d",&x,&y);
x=f[x];
y=f[y];
ins(x,y);
}
for(int i=1;i<=n;i++)if(vis[i]==0&&tarjan(i))
{
flag=1;
break;
}
puts(flag?"YES":"NO");
}
return 0;
}
/*
【trick&&吐槽】

【题意】

【类型】

【分析】

【时间复杂度&&优化】
O(n+m1+m2)

*/

#### 连通性Tarjan算法 双连通与强连通

2014-05-07 23:39:41

#### tarjan算法（边的双连通分量）

2015-08-09 18:05:06

#### Tarjan(无向图)有向图缩环/求(边双)强连通分量

2016-09-12 19:15:38

#### Tarjan三大算法之双连通分量（双连通分量）

2016-05-03 16:18:43

#### 强连通分量及缩点tarjan算法解析

2013-11-16 22:49:41

#### [双连通分量] tarjan算法

2017-07-26 20:09:50

#### 超详细Tarjan算法总结，求强连通分量，割点，割边，有重边的割边

2017-06-14 19:50:46

#### BZOJ 1718 浅谈边双连通分量tarjan求法

2017-08-19 19:47:18

#### Tarjan三大算法之双连通分量（割点，桥）

2016-04-23 11:25:35

#### CodeForces 216B Forming Teams（并查集判断奇数环）

2015-04-07 19:19:02