K LilaS的特殊图判断 - 第七届校赛正式赛 —— 补题
题目大意:
给定一个无向图,图中有 N N N 个顶点,编号为 1 − N 1-N 1−N , M M M 条边,编号为 1 − M 1-M 1−M 。第 i i i 条边连接顶点 u i u_i ui 和 v i v_i vi 。存在重边和自环。
有没有一种算法能快速判断该无向图中的每个连通部分是否满足:连通部分的顶点和边的数量相同
如果该图中每个连通部分都满足条件,则输出
Yes
;否则,输出No
。1 < = N < = 2 ∗ 1 0 5 1<=N<=2*10^5 1<=N<=2∗105
0 < = M < = 2 ∗ 1 0 5 0<=M<=2*10^5 0<=M<=2∗105
1 < = u i < = v i < = N 1<=u_i<=v_i<=N 1<=ui<=vi<=N
思路:
考虑并查集,维护祖先节点中 顶点个数 和 边的个数
int fa[N],sz[N],ver[N];
fa[i]=i,sz[i]=1,ver[i]=0;
int u,v;
u=find(u),v=find(v);
如果祖先节点相同,那么点的个数不用增加,考虑给祖先节点多加一条边
if(u==v){
ver[u]++;
}
如果祖先节点不相同,那么将这两个连通块合并,随便找一个节点为祖宗节点即可
else{
fa[v]=u;
sz[u]+=sz[v];
ver[u]+=ver[v]+1;//这条边
}
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define PII pair<int,int>
#define lowbit(x) x&-x
#define ALL(x) x.begin(),x.end()
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int fa[N],sz[N],ver[N];
int n,m;
int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void solve() {
cin>>n>>m;
for(int i=1;i<=n;i++){
fa[i]=i;
sz[i]=1;
ver[i]=0;
}
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
u=find(u),v=find(v);
if(u==v){
ver[u]++;
continue;
}
if(u!=v){
fa[v]=u;
sz[u]+=sz[v];
ver[u]+=ver[v]+1;
}else{
ver[u]++;
}
}
// cout<<'\n';
for(int i=1;i<=n;i++){
int u=find(i);
// cout<<sz[u]<<" "<<ver[u]<<'\n';
if(sz[u]!=ver[u]){
cout<<"No\n";
return ;
}
}
cout<<"Yes\n";
}
signed main() {
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T = 1;
// cin >> T;
while (T--) {
solve();
}
return 0;
}