B. Lawyers 题解
[ B. Lawyers ]( Problem - B - Codeforces )
写的不好凑合看qwq有问题私信或评论
单向边都可以连,双向边连一条即可。
我用的并查集做的,遍历所有边的时候如果是双向边就 join 连起来,然后如果两个点已经被连起来了,就说明出现了一个环,将这个环的祖宗节点标记1;如果是单向边就直接将B的祖宗节点标记1,其实整个问题就是将每个连通分量的祖宗节点标记为1,然后去找祖宗节点是否全被标记过。
代码
#include <bits/stdc++.h>
using namespace std;
//-------------------------------------------------------------------------------------------
#define int long long
#define lost_R ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define P pair<int,int>
#define lowbit(x) (x&(-x))
#define dbg1(x) cout<<"# "<<x<<endl
#define dbg2(x,y) cout<<"# "<<x<<" "<<y<<endl
#define endl '\n'
const int mod=998244353;
const int N=2e5+10;
const int INF=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
using ar3=array<int,3>;
using ar2=array<int,2>;
//--------------------------------------------------------------------------------------
int n,m;
int f[N], alive[N];
vector<P> g;
unordered_map<int, bool> mp;
void init(int n){
for(int i=1;i<=n;i++) f[i]=i, alive[i]=0;
}
int find(int x){
return f[x]==x?x:f[x]=find(f[x]);
}
void merge(int x, int y){
x=find(x), y=find(y);
if(x==y){ //成环
alive[x]=1;
return;
}
f[x]=y;
alive[y]|=alive[x]; //祖宗节点之间的继承
}
void solve(){
cin>>n>>m;
if(n<=2){
cout<<"NO"<<endl;
return;
}
init(n);
g.clear();
mp.clear();
auto hash_edge = [&](int x, int y){
return x*(n+1)+y;
};
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
g.push_back({a,b});
mp[hash_edge(a,b)]=true;
}
for(auto [u,v]:g){
if(mp.count(hash_edge(v,u))){
if(u<=v) merge(u,v); //确保双向连只连一条
}
else{
alive[find(v)]=1;
}
}
for(int i=1;i<=n;i++){
if(!alive[find(i)]){
cout<<"NO"<<endl;
return;
}
}
cout<<"YES"<<endl;
}
signed main(){
lost_R;
int T=1;
//cin>>T;
for(int i=1;i<=T;i++){
solve();
}
return 0;
}