Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) |
#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&&吐槽】
对于问题,如果其有多个因素怎么办?简化问题,拆开考虑!
【题意】
给你一个图,有n(1e6)个点,m1(1e6)条双向边,m2(1e6)条单向边。
对于双向边,只能走某个方向,即正着走过这条边就不能再反着走。
问你这个图上,是否可以从一点走回自己。
【类型】
并查集+强连通分量
【分析】
简化问题的思想很重要!
如果只有双向边,求是否有环即可,可以用并查集实现。
如果只有单向边,求是否有强连通分量即可,可以用tarjan实现。
现在两者都有,我们该怎么办?
我们可以先对于双向边并查集找环,找到环肯定YES,找不到环也把存在双向边的缩成了一个点。
事实上,这些点之间确实相当于一个点。
于是基于这个缩点后的结果,我们再根据单向边找强连通分量,这道题就做完啦,做完啦!
【时间复杂度&&优化】
O(n+m1+m2)
*/