Codeforces Round #599 (Div. 2) D. 0-1 MST (補圖連通塊計數)

 

Ujan has a lot of useless stuff in his drawers, a considerable part of which are his math notebooks: it is time to sort them out. This time he found an old dusty graph theory notebook with a description of a graph.ios

It is an undirected weighted graph on nn vertices. It is a complete graph: each pair of vertices is connected by an edge. The weight of each edge is either 00 or 11; exactly mm edges have weight 11, and all others have weight 00.c++

Since Ujan doesn't really want to organize his notes, he decided to find the weight of the minimum spanning tree of the graph. (The weight of a spanning tree is the sum of all its edges.) Can you find the answer for Ujan so he stops procrastinating?app

Input

The first line of the input contains two integers nn and mm (1n1051≤n≤105, 0mmin(n(n1)2,105)0≤m≤min(n(n−1)2,105)), the number of vertices and the number of edges of weight 11 in the graph.less

The ii-th of the next mm lines contains two integers aiai and bibi (1ai,bin1≤ai,bi≤n, aibiai≠bi), the endpoints of the ii-th edge of weight 11.ide

It is guaranteed that no edge appears twice in the input.spa

Output

Output a single integer, the weight of the minimum spanning tree of the graph.code

Examples
input
Copy
6 11
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6
output
Copy
2
input
Copy
3 0
output
Copy
0
Note

The graph from the first sample is shown below. Dashed edges have weight 00, other edges have weight 11. One of the minimum spanning trees is highlighted in orange and has total weight 22.orm

In the second sample, all edges have weight 00 so any spanning tree has total weight 00.xml

 

 

#include <iostream> #include <algorithm> #include <cstdio> #include <string> #include <cstring> #include <cstdlib> #include <map> #include <vector> #include <set> #include <queue> #include <stack> #include <cmath>
using namespace std; #define mem(s,t) memset(s,t,sizeof(s))
#define pq priority_queue
#define pb push_back
#define fi first
#define se second
#define ac return 0;
#define ll long long
#define cin2(a,n,m)     for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
#define rep_(n,m)  for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
#define rep(n) for(int i=1;i<=n;i++)
#define test(xxx) cout<<"  Test  " <<" "<<xxx<<endl;
#define TLE std::ios::sync_with_stdio(false);   cin.tie(NULL);   cout.tie(NULL);   cout.precision(10);
#define lc now<<1
#define rc now<<1|1
#define ls now<<1,l,mid
#define rs now<<1|1,mid+1,r
#define half no[now].l+((no[now].r-no[now].l)>>1)
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000000007
const int mxn = 1e5+10; int n,m,k,ans,col,t,flag,vis[mxn]; ll dp[mxn],pro[mxn]; string str,ch ; map<char,int>mp; set<int>st,G[mxn]; pair <int,int> pa[mxn]; bool cmp(pair<int,int>x,pair<int,int>y) { return x.first>y.first; } void BFS(int x) { queue<int>q; q.push(x); st.erase(x); while(q.size()) { int now = q.front(); q.pop(); if(vis[now]) continue; vis[now] = 1 ; for(set<int>::iterator it=st.begin(); it!=st.end();) { int cnt = *it; it++;//set和vector這些容器不能邊修改邊遍歷,須要在修改以前將迭代器日後加一
            if(G[now].find(cnt)==G[now].end()) { q.push(cnt); st.erase(cnt); } } } } int main() { cin>>n>>m; for(int i=1; i<=n; i++) st.insert(i); for(int i=1; i<=m; i++) { cin>>col>>ans; G[col].insert(ans); G[ans].insert(col); } ans = 0; for(int i=1; i<=n; i++) { if(!vis[i]) { BFS(i); ans++; } } cout<<ans-1<<endl; return 0; }

 

//聚聚:並查集,用set存已經被放入並查集的點,對於沒有放入的點,計算該點和聯通塊相連的點的個數,若是相連的點的個數小於聯通塊大小,則直接連進去便可。時間複雜度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; }
相關文章
相關標籤/搜索