当前位置 博文首页 > duanghaha的博客:【codeforces 1243】D. 0-1 MST(补图的连通块
给你一个图,求补图的连通块个数。
考虑用使用并查集,用set存已经被放入并查集的点,对于没有放入的点,计算该点和联通块相连的点的个数,如果相连的点的个数小于联通块大小,则直接连进去即可。时间复杂度 O ( n + m ? l o g ) O(n+m*log) O(n+m?log)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
int par[N],siz[N];
int cnt[N];
struct edge{
int u,v,w;
}e[N];
vector<int> G[N];
int find(int x){
return x==par[x]?x:par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return ;
par[x]=y;
siz[y]+=siz[x];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m,u,v;
cin>>n>>m;
for(int i=1;i<=n;i++){
par[i]=i;
siz[i]=1;
}
for(int i=1;i<=m;i++){
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
int ans=n-1;
set<int> st;
st.insert(1);
for(int i=2;i<=n;i++){
for(int v:G[i]){
cnt[find(v)]++;//和各联通块相连的点的个数
}
for(auto it=st.begin();it!=st.end();){
int an=find(*it);
if(cnt[an]<siz[an]){
unite(*it,i);
st.erase(it++);
ans--;
}else it++;
}
for(int v:G[i]) cnt[find(v)]=0;
st.insert(i);
}
cout<<ans<<endl;
return 0;
}
cs