#include <bits/stdc++.h>
#define task ""
#define ii pair<int, int>
#define pli pair<long long, int>
#define ll long long
#define ld long double
#define fi first
#define se second
#define faster ios_base::sync_with_stdio(false); cin.tie(nullptr);
#define F if(fopen(task".inp","r")){ freopen(task".inp","r",stdin); freopen(task".out","w",stdout); }
using namespace std;
const int Q = 1e6 + 21;
const int N = 1e5 + 21;
const int LOG = 20;
const int mod = 1e9 + 7;
const int inf = 1e9 + 7;
const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};
int n, m;
vector<int> adj[N];
int deg[N];
int cur_deg[N];
bool rem[N];
int color[N];
int best_k, best[N];
int vis[N], vis_timer = 0;
int in_nei[N], nei_timer = 0;
mt19937 rng(1337);
bool check_bipartite()
{
if(m == 0)
{
best_k = 1;
for(int i = 1; i <= n; i++) best[i] = 1;
return true;
}
for(int i = 1; i <= n; i++) color[i] = 0;
for(int i = 1; i <= n; i++)
{
if(color[i] != 0) continue;
color[i] = 1;
queue<int> q;
q.push(i);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int v : adj[u])
{
if(color[v] == 0)
{
color[v] = 3 - color[u];
q.push(v);
}
else if(color[v] == color[u])
{
return false;
}
}
}
}
best_k = 2;
for(int i = 1; i <= n; i++) best[i] = color[i];
return true;
}
bool kempe_color(int u)
{
vector<int> nei;
++nei_timer;
for(int v : adj[u])
{
if(color[v] >= 1 && color[v] <= 4)
{
nei.push_back(v);
in_nei[v] = nei_timer;
}
}
int last_w = -1, last_mask = -1;
vector<int> q;
q.reserve(n);
for(int step = 0; step < 45; step++)
{
int cnt[5] = {0, 0, 0, 0, 0};
int who[5][2];
for(int v : nei)
{
int c = color[v];
if(c >= 1 && c <= 4)
{
if(cnt[c] < 2) who[c][cnt[c]] = v;
cnt[c]++;
}
}
for(int c = 1; c <= 4; c++)
{
if(cnt[c] == 0)
{
color[u] = c;
return true;
}
}
vector<ii> pairs;
for(int c1 = 1; c1 <= 4; c1++)
{
if(cnt[c1] != 1) continue;
for(int c2 = c1 + 1; c2 <= 4; c2++)
{
if(cnt[c2] == 1)
pairs.push_back({c1, c2});
}
for(int c2 = 1; c2 <= 4; c2++)
{
if(cnt[c2] >= 2)
pairs.push_back({c1, c2});
}
}
shuffle(pairs.begin(), pairs.end(), rng);
struct StepBMove { int c1, c2, w; };
vector<StepBMove> stepB_moves;
vector<ii> deferred_pairs;
const int SMALL_LIMIT = 64;
for(auto &pr : pairs)
{
int c1 = pr.fi, c2 = pr.se;
int start_v = who[c1][0];
++vis_timer;
q.clear();
q.push_back(start_v);
vis[start_v] = vis_timer;
int reached_cnt = 0;
for(size_t head = 0; head < q.size(); head++)
{
int x = q[head];
for(int y : adj[x])
{
int cy = color[y];
if((cy == c1 || cy == c2) && vis[y] != vis_timer)
{
vis[y] = vis_timer;
q.push_back(y);
if(in_nei[y] == nei_timer && cy == c2)
reached_cnt++;
}
}
if(reached_cnt == cnt[c2] || (int)q.size() > SMALL_LIMIT)
break;
}
if(reached_cnt == cnt[c2])
continue;
if((int)q.size() <= SMALL_LIMIT)
{
if(reached_cnt == 0)
{
for(int x : q) color[x] = (color[x] == c1 ? c2 : c1);
color[u] = c1;
return true;
}
else if(cnt[c2] == 2 && reached_cnt == 1)
{
int w_unreached = (vis[who[c2][0]] == vis_timer) ? who[c2][1] : who[c2][0];
stepB_moves.push_back({c1, c2, w_unreached});
}
}
else
{
deferred_pairs.push_back(pr);
}
}
for(auto &pr : deferred_pairs)
{
int c1 = pr.fi, c2 = pr.se;
int start_v = who[c1][0];
++vis_timer;
q.clear();
q.push_back(start_v);
vis[start_v] = vis_timer;
int reached_cnt = 0;
for(size_t head = 0; head < q.size(); head++)
{
int x = q[head];
for(int y : adj[x])
{
int cy = color[y];
if((cy == c1 || cy == c2) && vis[y] != vis_timer)
{
vis[y] = vis_timer;
q.push_back(y);
if(in_nei[y] == nei_timer && cy == c2)
reached_cnt++;
}
}
if(reached_cnt == cnt[c2])
break;
}
if(reached_cnt == 0)
{
for(int x : q) color[x] = (color[x] == c1 ? c2 : c1);
color[u] = c1;
return true;
}
else if(cnt[c2] == 2 && reached_cnt == 1)
{
int w_unreached = (vis[who[c2][0]] == vis_timer) ? who[c2][1] : who[c2][0];
stepB_moves.push_back({c1, c2, w_unreached});
}
}
if(stepB_moves.empty()) break;
shuffle(stepB_moves.begin(), stepB_moves.end(), rng);
StepBMove chosen = stepB_moves[0];
for(auto &mv : stepB_moves)
{
int mask = (1 << mv.c1) | (1 << mv.c2);
if(mv.w != last_w || mask != last_mask)
{
chosen = mv;
break;
}
}
++vis_timer;
q.clear();
q.push_back(chosen.w);
vis[chosen.w] = vis_timer;
for(size_t head = 0; head < q.size(); head++)
{
int x = q[head];
for(int y : adj[x])
{
int cy = color[y];
if((cy == chosen.c1 || cy == chosen.c2) && vis[y] != vis_timer)
{
vis[y] = vis_timer;
q.push_back(y);
}
}
}
for(int x : q) color[x] = (color[x] == chosen.c1 ? chosen.c2 : chosen.c1);
last_w = chosen.w;
last_mask = (1 << chosen.c1) | (1 << chosen.c2);
}
return false;
}
void solve()
{
cin >> n >> m;
best_k = inf;
for(int i = 1; i <= n; i++)
{
adj[i].clear();
deg[i] = 0;
best[i] = 0;
}
for(int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
if(u == v) continue;
adj[u].push_back(v);
adj[v].push_back(u);
}
for(int i = 1; i <= n; i++)
{
sort(adj[i].begin(), adj[i].end());
adj[i].erase(unique(adj[i].begin(), adj[i].end()), adj[i].end());
deg[i] = adj[i].size();
}
if(check_bipartite())
{
cout << best_k << '\n';
for(int i = 1; i <= n; i++) cout << best[i] << " ";
cout << '\n';
return;
}
clock_t start_time = clock();
vector<bool> used(n + 2, false);
while(best_k > 4 && (double)(clock() - start_time) / CLOCKS_PER_SEC < 2.6)
{
for(int i = 1; i <= n; i++)
{
cur_deg[i] = deg[i];
rem[i] = false;
color[i] = 0;
}
priority_queue<pli, vector<pli>, greater<pli>> pq;
for(int i = 1; i <= n; i++)
{
pq.push({(1LL * cur_deg[i] << 30) | (rng() & 0x3FFFFFFF), i});
}
vector<int> order;
order.reserve(n);
while(!pq.empty())
{
auto p = pq.top();
pq.pop();
int u = p.se;
if(rem[u]) continue;
rem[u] = true;
order.push_back(u);
for(int v : adj[u])
{
if(!rem[v])
{
cur_deg[v]--;
pq.push({(1LL * cur_deg[v] << 30) | (rng() & 0x3FFFFFFF), v});
}
}
}
reverse(order.begin(), order.end());
int cur_k = 0;
for(int u : order)
{
int mask = 0;
for(int v : adj[u])
if(color[v] >= 1 && color[v] <= 4)
mask |= (1 << color[v]);
int chosen_c = 0;
for(int c = 1; c <= 4; c++)
{
if(!(mask & (1 << c)))
{
chosen_c = c;
break;
}
}
if(chosen_c > 0)
{
color[u] = chosen_c;
}
else if(!kempe_color(u))
{
for(int v : adj[u])
if(color[v] > 0) used[color[v]] = true;
for(int c = 1; c <= n; c++)
{
if(!used[c])
{
color[u] = c;
break;
}
}
for(int v : adj[u])
if(color[v] > 0) used[color[v]] = false;
}
cur_k = max(cur_k, color[u]);
if(cur_k >= best_k) break;
}
if(cur_k < best_k)
{
best_k = cur_k;
for(int i = 1; i <= n; i++)
best[i] = color[i];
}
}
cout << best_k << '\n';
for(int i = 1; i <= n; i++)
cout << best[i] << " ";
cout << '\n';
}
signed main()
{
faster;
F;
int test = 1;
while(test--)
{
solve();
}
cerr << "Time elapsed: " << (1.0 * clock() / CLOCKS_PER_SEC) << " s.\n";
return 0;
}