#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
struct Edge
{
int x, y;
};
Edge b[400005];
bool cmp1(Edge x, Edge y)
{
if(x.x != y.x) return x.x < y.x;
return x.y < y.y;
}
int n, m, x, y, cnt, maxn = 1, l[400005], a[200005], fa[200005];
bool flag[200005];
int fnd(int x)
{
if(x == fa[x]) return x;
return fa[x] = fnd(fa[x]);
}
inline void findEdge(int x)
{
int cur = 1;
for(int i = l[x]; i < l[x + 1]; i++)
{
while(cur < b[i].y)
{
fa[fnd(cur)] = fnd(x);
flag[cur] = true;
cur++;
}
cur++;
}
while(cur <= n)
{
fa[fnd(cur)] = fnd(x);
flag[cur] = true;
cur++;
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &b[i].x, &b[i].y);
b[i + m].x = b[i].y;
b[i + m].y = b[i].x;
}
m *= 2;
sort(b + 1, b + m + 1, cmp1);
for(int i = 1; i <= m; i++)
{
if(b[i].x != b[i - 1].x)
{
for(int j = b[i - 1].x + 1; j <= b[i].x; j++) l[j] = i;
}
}
for(int j = b[m].x + 1; j <= n + 1; j++) l[j] = m + 1;
for(int i = 1; i <= n; i++)
{
fa[i] = i;
if(l[i + 1] - l[i] < l[maxn + 1] - l[maxn]) maxn = i;
}
findEdge(maxn);
for(int i = 1; i <= n; i++)
{
if(!flag[i]) findEdge(i);
}
for(int i = 1; i <= n; i++)
{
if(a[fnd(i)] == 0) cnt++;
a[fnd(i)]++;
}
sort(a + 1, a + n + 1);
printf("%d\n", cnt);
for(int i = 1; i <= n; i++)
{
if(a[i] != 0) printf("%d ", a[i]);
}
return 0;
}
b 是存边的数组,l 是每个点在 b 数组中存放的起始位置,findEdge 是找一个点连接的所有边并且放入并查集,flag 是这个点有没有被放到并查集中。