[ 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;
}