题干:

You are given an undirected graph consisting of n vertices and  edges. Instead of giving you the edges that exist in the graph, we give you m unordered pairs (x, y) such that there is no edge between x and y, and if some pair of vertices is not listed in the input, then there is an edge between these vertices.

You have to find the number of connected components in the graph and the size of each component. A connected component is a set of vertices X such that for every two vertices from this set there exists at least one path in the graph connecting these vertices, but adding any other vertex to X violates this rule.

Input

The first line contains two integers n and m (1 ≤ n ≤ 200000, ).

Then m lines follow, each containing a pair of integers x and y (1 ≤ x, y ≤ nx ≠ y) denoting that there is no edge between x and y. Each pair is listed at most once; (x, y) and (y, x) are considered the same (so they are never listed in the same test). If some pair of vertices is not listed in the input, then there exists an edge between those vertices.

Output

Firstly print k — the number of connected components in this graph.

Then print k integers — the sizes of components. You should output these integers in non-descending order.

Example

Input

5 5
1 2
3 4
3 2
4 2
2 5

Output

2
1 4

题目大意:

无向图中给定n个顶点,m条不存在的边(除了这m条边,其余都存在),求图的连通分量,及每个连通分量的大小。

解题报告:

官方题解:

别从给定的边入手,而是直接对所有顶点bfs就可以了,可以证明复杂度是线性的,顶多加上容器自带的log。

【CodeForces - 920E】Connected Components? (dsu,补图连通块,STLset+map,bfs 或bitset)_#define

当然, 其实用不到upperbound,因为bfs就是边删除边进行的,不会涉及迭代器危机。但是dfs就比较危险了,下面代码就有对应官方题解的dfs。

AC代码1:(240ms)

vector维护当前还剩多少点没有被访问到(注意巧妙的O1维护方式,正常的维护需要On的时间)。map记录边的信息

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
map<int,bool> mp[MAX];
vector<int> vv,ans;
int bfs(int x) {
int res = 0;
queue<int> q;
q.push(x);
while(q.size()) {
int cur = q.front();q.pop();
res++;
// int up = vv.size();这里不能这样写,因为size是动态的。
for(int i = 0; i<(int)vv.size(); i++) {
int v = vv[i];
if(mp[cur].count(v) == 0) {
swap(vv[i],vv.back());//用来实现set的erase操作,减少常数。
vv.pop_back();//用来实现set的erase操作
i--;
q.push(v);
}
}
}
return res;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i = 1; i<=n; i++) vv.pb(i);
for(int x,y,i = 1; i<=m; i++) {
scanf("%d%d",&x,&y);
mp[x][y]=1;
mp[y][x]=1;
}
while(!vv.empty()) {
int v = vv.back();vv.pop_back();
int cnt = bfs(v);
ans.push_back(cnt);
}
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for(int i = 0; i<(int)ans.size(); i++) {
printf("%d ",ans[i]);
}

return 0 ;
}

 

AC代码2:

用set维护未被访问的点集,bfs中对于每一个点,先一遍操作,同时记录一个vector,然后再更新到set中(删除元素),这样避免了边操作边更新所带来的迭代器的变化,避免了 不好控制 的情况发生。

【CodeForces - 920E】Connected Components? (dsu,补图连通块,STLset+map,bfs 或bitset)_#include_02

 

AC代码3:

用map<int,set<int> > mp  来减小内存。(实际上也无所谓,直接开2e5个set一样的)

注意dfs中,用pair来接受一个map,也就是这里ip其实代表的就是一个pair。

这里也掌握一种姿势:就算是遇到AC代码2那种  set迭代器的问题的时候,第一可以用AC代码2那种处理方式,第二可以改用map:如果需要删除it,那就先将it记录到tmp中,然后删除it,然后再upperbound一下就可以了。

【CodeForces - 920E】Connected Components? (dsu,补图连通块,STLset+map,bfs 或bitset)_#define_03

AC代码4:

bitset维护未访问的点集。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#include<bitset>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
set<int> ss[MAX];
bitset<MAX> bs;
int n,m,ans[MAX],tot;
void dfs(int x) {
bs[x] = 0;ans[tot]++;
for(int i = bs._Find_first(); i<bs.size(); i = bs._Find_next(i)) {
if(ss[x].count(i) == 0) dfs(i);
}
}
int main()
{
cin>>n>>m;
for(int i = 1; i<=n; i++) bs[i] = 1;
for(int u,v,i = 1; i<=m; i++) {
scanf("%d%d",&u,&v);
ss[u].insert(v);ss[v].insert(u);
}
for(int i = 1; i<=n; i++) {
if(bs[i]) tot++,dfs(i);
}
printf("%d\n",tot);
sort(ans+1,ans+tot+1);
for(int i = 1; i<=tot; i++) {
printf("%d%c",ans[i],i == tot ? '\n' : ' ');
}

return 0 ;
}

贴一个更快的:

AC代码5:

//别人的代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
set<int>st;
vector<int> mp[MAX];
int ans[MAX];
int del[MAX];
int n,m,tot;
void Bfs(int x) {
tot++;
ans[tot]=1;
st.erase(x);
queue<int>s;
s.push(x);
while(!s.empty()) {
int u=s.front();
s.pop();
int cnt=0;
for(set<int>::iterator it=st.begin(); it!=st.end(); it++) {
int to=*it;
if(binary_search(mp[u].begin(),mp[u].end(),to) == 0) {
s.push(to);
ans[tot]++;
del[++cnt]=to;
}
}
for(int i=1; i<=cnt; i++)st.erase(del[i]);
}
}
int main()
{
scanf("%d%d",&n,&m);
tot=0;
st.clear();
for(int i=1; i<=m; i++) {
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
for(int i=1; i<=n; i++)st.insert(i),sort(mp[i].begin(),mp[i].end());
for(int i=1; i<=n; i++) {
if(st.count(i))Bfs(i);
}
printf("%d\n",tot);
sort(ans+1,ans+tot+1);
for(int i=1; i<=tot; i++) {
printf("%d ",ans[i]);
}
}