#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

const int mod = (int) 1e9 + 7;

void add(int &x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int mult(int x, int y) {
  return (long long) x * y % mod;
}

int myPower(int x, int pw) {
  int res = 1;
  for (; pw; pw >>= 1) {
    if (pw & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
  }
  return res;
}

void precalc() {
}

const int maxn = (int) 1e5 + 10;
int n, m;

vector<pair<int, int> > ps;

int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  ps.clear();
  for (int i = 0; i < m; ++i) {
    int s, t;
    scanf("%d%d", &s, &t);
    --s, --t;
    if (s > t) {
      swap(s, t);
    }
    ps.pb(mp(s, t));
  }
  return 1;
}

int ans[maxn];

map<pair<int, int>, int> ids;

vector<vector<int> > lefts;

vector<pair<int, int> > perm;

int best;
pair<int, int> skill;

void gen(int pos, int m) {
  assert(sz(lefts[pos]));
  for (int i = 0; i < sz(lefts[pos]); ++i) {
    perm.pb(mp(lefts[pos][i], pos));
    //eprintf("add (%d,%d)\n", perm.back().first, perm.back().second);
  }

  int mxin = 0;
  int sumin = 0;

  int who = 0;
  for (int j = pos - 1;;) {
    //eprintf("pos = %d, j = %d, search for %d\n", pos, j, lefts[pos][who]);
    assert(j >= 0);
    assert(who < sz(lefts[pos]));
    if (j == lefts[pos][who]) {
      int val = max(mxin, m - sumin);
      //eprintf("val = %d\n", val);
      ++sumin;
      if (best > val) {
        best = val;
        skill = mp(j, pos);
      }
      mxin = max(mxin, sumin);
      ++who;
    }
    if (who == sz(lefts[pos])) {
      break;
    }
    if (sz(lefts[j])) {
      int cnt0 = sz(perm);
      gen(j, m);
      int curs = sz(perm) - cnt0;
      mxin = max(mxin, curs);
      sumin += curs;
      j = lefts[j].back();
    } else {
      --j;
    }
  }
}

void solve(int col, vector<int> vs, vector<pair<int, int> > ps) {
  int n = sz(vs);
  /*eprintf("solve n = %d\n", n);
  for (int i = 0; i < sz(vs); ++i) {
    eprintf("%d%c", vs[i], " \n"[i == sz(vs) - 1]);
  }
  for (int i = 0; i < sz(ps); ++i) {
    eprintf("%d %d\n", ps[i].first, ps[i].second);
  }*/

  lefts = vector<vector<int> >(n);
  for (int i = 0; i < sz(ps); ++i) {
    int x = ps[i].first, y = ps[i].second;
    assert(x < y);
    lefts[y].pb(x);
  }
  lefts[n - 1].pb(0);

  for (int i = 0; i < n; ++i) {
    sort(lefts[i].begin(), lefts[i].end());
    reverse(lefts[i].begin(), lefts[i].end());
  }
  perm.clear();
  best = inf;
  skill = mp(-1, -1);
  gen(n - 1, sz(ps));
  if (::n == n) {
    ids.clear();
    for (int i = 0; i < sz(perm); ++i) {
      ids[perm[i]] = sz(perm) - 1 - i;
    }
  }
  assert(sz(perm) == sz(ps) + 1);
  //eprintf("found best = %d, (%d,%d)\n", best, skill.first, skill.second);
  auto skill = ::skill;
  //eprintf("color %d with %d\n", ids.at(mp(vs[skill.first], vs[skill.second])), col);
  int &toup = ans[ids.at(mp(vs[skill.first], vs[skill.second]))];
  assert(toup == -1);
  toup = col;
  //eprintf("%d %d\n", best, sz(ps));
  assert(best * 2 <= sz(ps) + 1);
  if (!sz(ps)) {
    return;
  }
  vector<pair<vector<pair<int, int> >, vector<int> > > touse;
  vector<pair<int, int> > nps;
  vector<int> nvs;
  {
    for (int i = 0; i < n; ++i) {
      if (i <= skill.first || i >= skill.second) {
        nvs.pb(vs[i]);
      }
    }
    if (sz(nvs) > 2) {
      nps.clear();
      for (int i = 0; i < sz(ps); ++i) {
        if (ps[i] == skill) {
          continue;
        }
        if (!(skill.first < ps[i].first && ps[i].first < skill.second) &&
            !(skill.first < ps[i].second && ps[i].second < skill.second)) {
          int xs[2] = {ps[i].first, ps[i].second};
          for (int it = 0; it < 2; ++it) {
            if (xs[it] >= skill.second) {
              xs[it] -= skill.second - skill.first - 1;
            }
          }
          nps.pb(mp(xs[0], xs[1]));
        }
      }
      touse.pb(mp(nps, nvs));
    }
  }
  for (int j = skill.second; j > skill.first;) {
    int it = sz(lefts[j]) - 1;
    if (j == skill.second) {
      while (it >= 0 && lefts[j][it] <= skill.first) {
        --it;
      }
    }
    if (it == -1) {
      --j;
      continue;
    }
    int l = lefts[j][it], r = j;
    nvs.clear();
    for (int i = l; i <= r; ++i) {
      nvs.pb(vs[i]);
    }
    nps.clear();
    for (int k = r; k > l; --k) {
      for (int x : lefts[k]) {
        if (k < r || x > l) {
          nps.pb(mp(x - l, k - l));
        }
      }
    }
    touse.pb(mp(nps, nvs));
    j = l;
  }

  for (auto &cur : touse) {
    solve(col + 1, cur.second, cur.first);
  }
}

void solve() {
  vector<int> vs;
  for (int i = 0; i < n; ++i) {
    vs.pb(i);
  }
  for (int i = 0; i <= sz(ps); ++i) {
    ans[i] = -1;
  }
  solve(0, vs, ps);
  for (int i = 0; i <= sz(ps); ++i) {
    assert(ans[i] >= 0);
    printf("%d%c", 1 + ans[i], " \n"[i == sz(ps)]);
  }
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

const int mod = (int) 1e9 + 7;

void add(int &x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int mult(int x, int y) {
  return (long long) x * y % mod;
}

int myPower(int x, int pw) {
  int res = 1;
  for (; pw; pw >>= 1) {
    if (pw & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
  }
  return res;
}

void precalc() {
}

const int maxn = (int) 1e5 + 10;
int n, m;

vector<pair<int, int> > ps;

int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  ps.clear();
  for (int i = 0; i < m; ++i) {
    int s, t;
    scanf("%d%d", &s, &t);
    --s, --t;
    if (s > t) {
      swap(s, t);
    }
    ps.pb(mp(s, t));
  }
  return 1;
}

int ans[maxn];

map<pair<int, int>, int> ids;

vector<vector<int> > lefts;

vector<pair<int, int> > perm;

int best;
pair<int, int> skill;

void gen(int pos, int m) {
  assert(sz(lefts[pos]));
  for (int i = 0; i < sz(lefts[pos]); ++i) {
    perm.pb(mp(lefts[pos][i], pos));
    //eprintf("add (%d,%d)\n", perm.back().first, perm.back().second);
  }

  int mxin = 0;
  int sumin = 0;

  int who = 0;
  for (int j = pos - 1;;) {
    //eprintf("pos = %d, j = %d, search for %d\n", pos, j, lefts[pos][who]);
    assert(j >= 0);
    assert(who < sz(lefts[pos]));
    if (j == lefts[pos][who]) {
      int val = max(mxin, m - sumin);
      //eprintf("val = %d\n", val);
      ++sumin;
      if (best > val) {
        best = val;
        skill = mp(j, pos);
      }
      mxin = max(mxin, sumin);
      ++who;
    }
    if (who == sz(lefts[pos])) {
      break;
    }
    if (sz(lefts[j])) {
      int cnt0 = sz(perm);
      gen(j, m);
      int curs = sz(perm) - cnt0;
      mxin = max(mxin, curs);
      sumin += curs;
      j = lefts[j].back();
    } else {
      --j;
    }
  }
}

void solve(int col, vector<int> vs, vector<pair<int, int> > ps) {
  int n = sz(vs);
  /*eprintf("solve n = %d\n", n);
  for (int i = 0; i < sz(vs); ++i) {
    eprintf("%d%c", vs[i], " \n"[i == sz(vs) - 1]);
  }
  for (int i = 0; i < sz(ps); ++i) {
    eprintf("%d %d\n", ps[i].first, ps[i].second);
  }*/

  lefts = vector<vector<int> >(n);
  for (int i = 0; i < sz(ps); ++i) {
    int x = ps[i].first, y = ps[i].second;
    assert(x < y);
    lefts[y].pb(x);
  }
  lefts[n - 1].pb(0);

  for (int i = 0; i < n; ++i) {
    sort(lefts[i].begin(), lefts[i].end());
    reverse(lefts[i].begin(), lefts[i].end());
  }
  perm.clear();
  best = inf;
  skill = mp(-1, -1);
  gen(n - 1, sz(ps));
  if (::n == n) {
    ids.clear();
    for (int i = 0; i < sz(perm); ++i) {
      ids[perm[i]] = sz(perm) - 1 - i;
    }
  }
  assert(sz(perm) == sz(ps) + 1);
  //eprintf("found best = %d, (%d,%d)\n", best, skill.first, skill.second);
  auto skill = ::skill;
  //eprintf("color %d with %d\n", ids.at(mp(vs[skill.first], vs[skill.second])), col);
  ans[ids.at(mp(vs[skill.first], vs[skill.second]))] = col;
  //eprintf("%d %d\n", best, sz(ps));
  assert(best * 2 <= sz(ps) + 1);
  if (!sz(ps)) {
    return;
  }
  vector<pair<vector<pair<int, int> >, vector<int> > > touse;
  vector<pair<int, int> > nps;
  vector<int> nvs;
  {
    for (int i = 0; i < n; ++i) {
      if (i <= skill.first || i >= skill.second) {
        nvs.pb(vs[i]);
      }
    }
    nps.clear();
    for (int i = 0; i < sz(ps); ++i) {
      if (ps[i] == skill) {
        continue;
      }
      if (!(skill.first < ps[i].first && ps[i].first < skill.second) &&
          !(skill.first < ps[i].second && ps[i].second < skill.second)) {
        int xs[2] = {ps[i].first, ps[i].second};
        for (int it = 0; it < 2; ++it) {
          if (xs[it] >= skill.second) {
            xs[it] -= skill.second - skill.first - 1;
          }
        }
        nps.pb(mp(xs[0], xs[1]));
      }
    }
    touse.pb(mp(nps, nvs));
  }
  for (int j = skill.second; j > skill.first;) {
    int it = sz(lefts[j]) - 1;
    if (j == skill.second) {
      while (it >= 0 && lefts[j][it] <= skill.first) {
        --it;
      }
    }
    if (it == -1) {
      --j;
      continue;
    }
    int l = lefts[j][it], r = j;
    nvs.clear();
    for (int i = l; i <= r; ++i) {
      nvs.pb(vs[i]);
    }
    nps.clear();
    for (int k = r; k > l; --k) {
      for (int x : lefts[k]) {
        if (k < r || x > l) {
          nps.pb(mp(x - l, k - l));
        }
      }
    }
    touse.pb(mp(nps, nvs));
    j = l;
  }

  for (auto &cur : touse) {
    solve(col + 1, cur.second, cur.first);
  }
}

void solve() {
  vector<int> vs;
  for (int i = 0; i < n; ++i) {
    vs.pb(i);
  }
  for (int i = 0; i <= sz(ps); ++i) {
    ans[i] = -1;
  }
  solve(0, vs, ps);
  for (int i = 0; i <= sz(ps); ++i) {
    assert(ans[i] >= 0);
    printf("%d%c", 1 + ans[i], " \n"[i == sz(ps)]);
  }
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

const int mod = (int) 1e9 + 7;

void add(int &x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int mult(int x, int y) {
  return (long long) x * y % mod;
}

int myPower(int x, int pw) {
  int res = 1;
  for (; pw; pw >>= 1) {
    if (pw & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
  }
  return res;
}

void precalc() {
}

const int maxn = (int) 1e5 + 10;
int n, m;

vector<pair<int, int> > ps;

int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  ps.clear();
  for (int i = 0; i < m; ++i) {
    int s, t;
    scanf("%d%d", &s, &t);
    --s, --t;
    if (s > t) {
      swap(s, t);
    }
    ps.pb(mp(s, t));
  }
  return 1;
}

int ans[maxn];

map<pair<int, int>, int> ids;

vector<vector<int> > lefts;

vector<pair<int, int> > perm;

int best;
pair<int, int> skill;

void gen(int pos, int m) {
  assert(sz(lefts[pos]));
  for (int i = 0; i < sz(lefts[pos]); ++i) {
    perm.pb(mp(lefts[pos][i], pos));
    //eprintf("add (%d,%d)\n", perm.back().first, perm.back().second);
  }

  int mxin = 0;
  int sumin = 0;

  int who = 0;
  for (int j = pos - 1;;) {
    //eprintf("pos = %d, j = %d, search for %d\n", pos, j, lefts[pos][who]);
    assert(j >= 0);
    assert(who < sz(lefts[pos]));
    if (j == lefts[pos][who]) {
      int val = max(mxin, m - sumin);
      //eprintf("val = %d\n", val);
      ++sumin;
      if (best > val) {
        best = val;
        skill = mp(j, pos);
      }
      mxin = max(mxin, sumin);
      ++who;
    }
    if (who == sz(lefts[pos])) {
      break;
    }
    if (sz(lefts[j])) {
      int cnt0 = sz(perm);
      gen(j, m);
      int curs = sz(perm) - cnt0;
      mxin = max(mxin, curs);
      sumin += curs;
      j = lefts[j].back();
    } else {
      --j;
    }
  }
}

void solve(int col, vector<int> vs, vector<pair<int, int> > ps) {
  int n = sz(vs);
  /*eprintf("solve n = %d\n", n);
  for (int i = 0; i < sz(vs); ++i) {
    eprintf("%d%c", vs[i], " \n"[i == sz(vs) - 1]);
  }
  for (int i = 0; i < sz(ps); ++i) {
    eprintf("%d %d\n", ps[i].first, ps[i].second);
  }*/

  lefts = vector<vector<int> >(n);
  for (int i = 0; i < sz(ps); ++i) {
    int x = ps[i].first, y = ps[i].second;
    assert(x < y);
    lefts[y].pb(x);
  }
  lefts[n - 1].pb(0);

  for (int i = 0; i < n; ++i) {
    sort(lefts[i].begin(), lefts[i].end());
    reverse(lefts[i].begin(), lefts[i].end());
  }
  perm.clear();
  best = inf;
  skill = mp(-1, -1);
  gen(n - 1, sz(ps));
  if (::n == n) {
    ids.clear();
    for (int i = 0; i < sz(perm); ++i) {
      ids[perm[i]] = sz(perm) - 1 - i;
    }
  }
  assert(sz(perm) == sz(ps) + 1);
  //eprintf("found best = %d, (%d,%d)\n", best, skill.first, skill.second);
  auto skill = ::skill;
  //eprintf("color %d with %d\n", ids.at(mp(vs[skill.first], vs[skill.second])), col);
  ans[ids.at(mp(vs[skill.first], vs[skill.second]))] = col;
  //eprintf("%d %d\n", best, sz(ps));
  assert(best * 2 <= sz(ps) + 1);
  if (!sz(ps)) {
    return;
  }
  vector<pair<vector<pair<int, int> >, vector<int> > > touse;
  vector<pair<int, int> > nps;
  vector<int> nvs;
  {
    for (int i = 0; i < n; ++i) {
      if (i <= skill.first || i >= skill.second) {
        nvs.pb(vs[i]);
      }
    }
    if (sz(nvs)) {
      nps.clear();
      for (int i = 0; i < sz(ps); ++i) {
        if (ps[i] == skill) {
          continue;
        }
        if (!(skill.first < ps[i].first && ps[i].first < skill.second) &&
            !(skill.first < ps[i].second && ps[i].second < skill.second)) {
          int xs[2] = {ps[i].first, ps[i].second};
          for (int it = 0; it < 2; ++it) {
            if (xs[it] >= skill.second) {
              xs[it] -= skill.second - skill.first - 1;
            }
          }
          nps.pb(mp(xs[0], xs[1]));
        }
      }
      touse.pb(mp(nps, nvs));
    }
  }
  for (int j = skill.second; j > skill.first;) {
    int it = sz(lefts[j]) - 1;
    if (j == skill.second) {
      while (it >= 0 && lefts[j][it] <= skill.first) {
        --it;
      }
    }
    if (it == -1) {
      --j;
      continue;
    }
    int l = lefts[j][it], r = j;
    nvs.clear();
    for (int i = l; i <= r; ++i) {
      nvs.pb(vs[i]);
    }
    nps.clear();
    for (int k = r; k > l; --k) {
      for (int x : lefts[k]) {
        if (k < r || x > l) {
          nps.pb(mp(x - l, k - l));
        }
      }
    }
    touse.pb(mp(nps, nvs));
    j = l;
  }

  for (auto &cur : touse) {
    solve(col + 1, cur.second, cur.first);
  }
}

void solve() {
  vector<int> vs;
  for (int i = 0; i < n; ++i) {
    vs.pb(i);
  }
  for (int i = 0; i <= sz(ps); ++i) {
    ans[i] = -1;
  }
  solve(0, vs, ps);
  for (int i = 0; i <= sz(ps); ++i) {
    assert(ans[i] >= 0);
    printf("%d%c", 1 + ans[i], " \n"[i == sz(ps)]);
  }
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

const int mod = (int) 1e9 + 7;

void add(int &x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int mult(int x, int y) {
  return (long long) x * y % mod;
}

int myPower(int x, int pw) {
  int res = 1;
  for (; pw; pw >>= 1) {
    if (pw & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
  }
  return res;
}

void precalc() {
}

const int maxn = (int) 1e5 + 10;
int n, m;

vector<pair<int, int> > ps;

int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  ps.clear();
  for (int i = 0; i < m; ++i) {
    int s, t;
    scanf("%d%d", &s, &t);
    --s, --t;
    if (s > t) {
      swap(s, t);
    }
    ps.pb(mp(s, t));
  }
  return 1;
}

int ans[maxn];

map<pair<int, int>, int> ids;

vector<vector<int> > lefts;

vector<pair<int, int> > perm;

int best;
pair<int, int> skill;

void gen(int pos, int m) {
  assert(sz(lefts[pos]));
  for (int i = 0; i < sz(lefts[pos]); ++i) {
    perm.pb(mp(lefts[pos][i], pos));
    //eprintf("add (%d,%d)\n", perm.back().first, perm.back().second);
  }

  int mxin = 0;
  int sumin = 0;

  int who = 0;
  for (int j = pos - 1;;) {
    //eprintf("pos = %d, j = %d, search for %d\n", pos, j, lefts[pos][who]);
    assert(j >= 0);
    assert(who < sz(lefts[pos]));
    if (j == lefts[pos][who]) {
      if (sumin < m) {
        int val = max(mxin, m - sumin);
        //eprintf("val = %d\n", val);
        ++sumin;
        if (best > val) {
          best = val;
          skill = mp(j, pos);
        }
        mxin = max(mxin, sumin);
      }
      ++who;
    }
    if (who == sz(lefts[pos])) {
      break;
    }
    if (sz(lefts[j])) {
      int cnt0 = sz(perm);
      gen(j, m);
      int curs = sz(perm) - cnt0;
      mxin = max(mxin, curs);
      sumin += curs;
      j = lefts[j].back();
    } else {
      --j;
    }
  }
}

void solve(int col, vector<int> vs, vector<pair<int, int> > ps) {
  int n = sz(vs);
  /*eprintf("solve n = %d\n", n);
  for (int i = 0; i < sz(vs); ++i) {
    eprintf("%d%c", vs[i], " \n"[i == sz(vs) - 1]);
  }
  for (int i = 0; i < sz(ps); ++i) {
    eprintf("%d %d\n", ps[i].first, ps[i].second);
  }*/

  lefts = vector<vector<int> >(n);
  for (int i = 0; i < sz(ps); ++i) {
    int x = ps[i].first, y = ps[i].second;
    assert(x < y);
    lefts[y].pb(x);
  }
  lefts[n - 1].pb(0);

  for (int i = 0; i < n; ++i) {
    sort(lefts[i].begin(), lefts[i].end());
    reverse(lefts[i].begin(), lefts[i].end());
  }
  perm.clear();
  best = inf;
  skill = mp(0, n - 1);
  gen(n - 1, sz(ps));
  if (::n == n) {
    ids.clear();
    for (int i = 0; i < sz(perm); ++i) {
      ids[perm[i]] = sz(perm) - 1 - i;
    }
  }
  assert(sz(perm) == sz(ps) + 1);
  //eprintf("found best = %d, (%d,%d)\n", best, skill.first, skill.second);
  auto skill = ::skill;
  //eprintf("color %d with %d\n", ids.at(mp(vs[skill.first], vs[skill.second])), col);
  ans[ids.at(mp(vs[skill.first], vs[skill.second]))] = col;
  if (skill == mp(0, n - 1)) {
    return;
  }
  vector<pair<vector<pair<int, int> >, vector<int> > > touse;
  vector<pair<int, int> > nps;
  vector<int> nvs;
  {
    for (int i = 0; i < n; ++i) {
      if (i <= skill.first || i >= skill.second) {
        nvs.pb(vs[i]);
      }
    }
    nps.clear();
    for (int i = 0; i < sz(ps); ++i) {
      if (ps[i] == skill) {
        continue;
      }
      if (!(skill.first < ps[i].first && ps[i].first < skill.second) &&
          !(skill.first < ps[i].second && ps[i].second < skill.second)) {
        int xs[2] = {ps[i].first, ps[i].second};
        for (int it = 0; it < 2; ++it) {
          if (xs[it] >= skill.second) {
            xs[it] -= skill.second - skill.first - 1;
          }
        }
        nps.pb(mp(xs[0], xs[1]));
      }
    }
    touse.pb(mp(nps, nvs));
  }
  for (int j = skill.second; j > skill.first;) {
    int it = sz(lefts[j]) - 1;
    if (j == skill.second) {
      while (it >= 0 && lefts[j][it] <= skill.first) {
        --it;
      }
    }
    if (it == -1) {
      --j;
      continue;
    }
    int l = lefts[j][it], r = j;
    nvs.clear();
    for (int i = l; i <= r; ++i) {
      nvs.pb(vs[i]);
    }
    nps.clear();
    for (int k = r; k > l; --k) {
      for (int x : lefts[k]) {
        if (k < r || x > l) {
          nps.pb(mp(x - l, k - l));
        }
      }
    }
    touse.pb(mp(nps, nvs));
    j = l;
  }

  for (auto &cur : touse) {
    solve(col + 1, cur.second, cur.first);
  }
}

void solve() {
  vector<int> vs;
  for (int i = 0; i < n; ++i) {
    vs.pb(i);
  }
  for (int i = 0; i <= sz(ps); ++i) {
    ans[i] = -1;
  }
  solve(0, vs, ps);
  for (int i = 0; i <= sz(ps); ++i) {
    assert(ans[i] >= 0);
    printf("%d%c", 1 + ans[i], " \n"[i == sz(ps)]);
  }
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

const int mod = (int) 1e9 + 7;

void add(int &x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int mult(int x, int y) {
  return (long long) x * y % mod;
}

int myPower(int x, int pw) {
  int res = 1;
  for (; pw; pw >>= 1) {
    if (pw & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
  }
  return res;
}

void precalc() {
}

const int maxn = (int) 1e5 + 10;
int n, m;

vector<pair<int, int> > ps;

int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  ps.clear();
  for (int i = 0; i < m; ++i) {
    int s, t;
    scanf("%d%d", &s, &t);
    --s, --t;
    if (s > t) {
      swap(s, t);
    }
    ps.pb(mp(s, t));
  }
  return 1;
}

int ans[maxn];

map<pair<int, int>, int> ids;

vector<vector<int> > lefts;

vector<pair<int, int> > perm;

int best;
pair<int, int> skill;

void gen(int pos, int m) {
  assert(sz(lefts[pos]));
  for (int i = 0; i < sz(lefts[pos]); ++i) {
    perm.pb(mp(lefts[pos][i], pos));
    //eprintf("add (%d,%d)\n", perm.back().first, perm.back().second);
  }

  int mxin = 0;
  int sumin = 0;

  int who = 0;
  for (int j = pos - 1;;) {
    if (j == lefts[pos][who]) {
      int val = max(mxin, m - sumin);
      ++sumin;
      if (best > val) {
        best = val;
        skill = mp(j, pos);
      }
      mxin = max(mxin, sumin);
      ++who;
    }
    if (who == sz(lefts[pos])) {
      break;
    }
    if (sz(lefts[j])) {
      int cnt0 = sz(perm);
      gen(j, m);
      int curs = sz(perm) - cnt0;
      mxin = max(mxin, curs);
      sumin += curs;
      j = lefts[j].back();
    } else {
      --j;
    }
  }
}

void solve(int col, vector<int> vs, vector<pair<int, int> > ps) {
  int n = sz(vs);
  /*eprintf("solve n = %d\n", n);
  for (int i = 0; i < sz(vs); ++i) {
    eprintf("%d%c", vs[i], " \n"[i == sz(vs) - 1]);
  }
  for (int i = 0; i < sz(ps); ++i) {
    eprintf("%d %d\n", ps[i].first, ps[i].second);
  }*/

  lefts = vector<vector<int> >(n);
  for (int i = 0; i < sz(ps); ++i) {
    int x = ps[i].first, y = ps[i].second;
    assert(x < y);
    lefts[y].pb(x);
  }
  lefts[n - 1].pb(0);

  for (int i = 0; i < n; ++i) {
    sort(lefts[i].begin(), lefts[i].end());
    reverse(lefts[i].begin(), lefts[i].end());
  }
  perm.clear();
  best = inf;
  skill = mp(-1, -1);
  gen(n - 1, sz(ps));
  if (::n == n) {
    ids.clear();
    for (int i = 0; i < sz(perm); ++i) {
      ids[perm[i]] = sz(perm) - 1 - i;
    }
  }
  assert(sz(perm) == sz(ps) + 1);
  assert(best < inf);
  //eprintf("found best = %d, (%d,%d)\n", best, skill.first, skill.second);
  auto skill = ::skill;
  //eprintf("color %d with %d\n", ids.at(mp(vs[skill.first], vs[skill.second])), col);
  ans[ids.at(mp(vs[skill.first], vs[skill.second]))] = col;
  if (skill == mp(0, n - 1)) {
    return;
  }
  vector<pair<vector<pair<int, int> >, vector<int> > > touse;
  vector<pair<int, int> > nps;
  vector<int> nvs;
  {
    for (int i = 0; i < n; ++i) {
      if (i <= skill.first || i >= skill.second) {
        nvs.pb(vs[i]);
      }
    }
    nps.clear();
    for (int i = 0; i < sz(ps); ++i) {
      if (ps[i] == skill) {
        continue;
      }
      if (!(skill.first < ps[i].first && ps[i].first < skill.second) &&
          !(skill.first < ps[i].second && ps[i].second < skill.second)) {
        int xs[2] = {ps[i].first, ps[i].second};
        for (int it = 0; it < 2; ++it) {
          if (xs[it] >= skill.second) {
            xs[it] -= skill.second - skill.first - 1;
          }
        }
        nps.pb(mp(xs[0], xs[1]));
      }
    }
    touse.pb(mp(nps, nvs));
  }
  for (int j = skill.second; j > skill.first;) {
    int it = sz(lefts[j]) - 1;
    if (j == skill.second) {
      while (it >= 0 && lefts[j][it] <= skill.first) {
        --it;
      }
    }
    if (it == -1) {
      --j;
      continue;
    }
    int l = lefts[j][it], r = j;
    nvs.clear();
    for (int i = l; i <= r; ++i) {
      nvs.pb(vs[i]);
    }
    nps.clear();
    for (int k = r; k > l; --k) {
      for (int x : lefts[k]) {
        if (k < r || x > l) {
          nps.pb(mp(x - l, k - l));
        }
      }
    }
    touse.pb(mp(nps, nvs));
    j = l;
  }

  for (auto &cur : touse) {
    solve(col + 1, cur.second, cur.first);
  }
}

void solve() {
  vector<int> vs;
  for (int i = 0; i < n; ++i) {
    vs.pb(i);
  }
  for (int i = 0; i <= sz(ps); ++i) {
    ans[i] = -1;
  }
  solve(0, vs, ps);
  for (int i = 0; i <= sz(ps); ++i) {
    assert(ans[i] >= 0);
    printf("%d%c", 1 + ans[i], " \n"[i == sz(ps)]);
  }
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

const int mod = (int) 1e9 + 7;

void add(int &x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int mult(int x, int y) {
  return (long long) x * y % mod;
}

int myPower(int x, int pw) {
  int res = 1;
  for (; pw; pw >>= 1) {
    if (pw & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
  }
  return res;
}

void precalc() {
}

const int maxn = (int) 1e5 + 10;
int n, m;

vector<pair<int, int> > ps;

int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  ps.clear();
  for (int i = 0; i < m; ++i) {
    int s, t;
    scanf("%d%d", &s, &t);
    --s, --t;
    if (s > t) {
      swap(s, t);
    }
    ps.pb(mp(s, t));
  }
  return 1;
}

int ans[maxn];

map<pair<int, int>, int> ids;

vector<vector<int> > lefts;

vector<pair<int, int> > perm;

int best;
pair<int, int> skill;

void gen(int pos, int m) {
  assert(sz(lefts[pos]));
  for (int i = 0; i < sz(lefts[pos]); ++i) {
    perm.pb(mp(lefts[pos][i], pos));
    //eprintf("add (%d,%d)\n", perm.back().first, perm.back().second);
  }

  int mxin = 0;
  int sumin = 0;

  int who = 0;
  for (int j = pos - 1;;) {
    if (j == lefts[pos][who]) {
      ++sumin;
      int val = max(mxin, m - sumin);
      if (best > val) {
        best = val;
        skill = mp(j, pos);
      }
      ++who;
    }
    if (who == sz(lefts[pos])) {
      break;
    }
    if (sz(lefts[j])) {
      int cnt0 = sz(perm);
      gen(j, m);
      int curs = sz(perm) - cnt0;
      mxin = max(mxin, curs);
      sumin += curs;
      j = lefts[j].back();
    } else {
      --j;
    }
  }
}

void solve(int col, vector<int> vs, vector<pair<int, int> > ps) {
  int n = sz(vs);
  /*eprintf("solve n = %d\n", n);
  for (int i = 0; i < sz(vs); ++i) {
    eprintf("%d%c", vs[i], " \n"[i == sz(vs) - 1]);
  }
  for (int i = 0; i < sz(ps); ++i) {
    eprintf("%d %d\n", ps[i].first, ps[i].second);
  }*/

  lefts = vector<vector<int> >(n);
  for (int i = 0; i < sz(ps); ++i) {
    int x = ps[i].first, y = ps[i].second;
    assert(x < y);
    lefts[y].pb(x);
  }
  lefts[n - 1].pb(0);

  for (int i = 0; i < n; ++i) {
    sort(lefts[i].begin(), lefts[i].end());
    reverse(lefts[i].begin(), lefts[i].end());
  }
  perm.clear();
  best = inf;
  skill = mp(-1, -1);
  gen(n - 1, sz(ps));
  if (::n == n) {
    ids.clear();
    for (int i = 0; i < sz(perm); ++i) {
      ids[perm[i]] = sz(perm) - 1 - i;
    }
  }
  assert(sz(perm) == sz(ps) + 1);
  assert(best < inf);
  //eprintf("found best = %d, (%d,%d)\n", best, skill.first, skill.second);
  auto skill = ::skill;
  //eprintf("color %d with %d\n", ids.at(mp(vs[skill.first], vs[skill.second])), col);
  ans[ids.at(mp(vs[skill.first], vs[skill.second]))] = col;
  if (skill == mp(0, n - 1)) {
    return;
  }
  vector<pair<vector<pair<int, int> >, vector<int> > > touse;
  vector<pair<int, int> > nps;
  vector<int> nvs;
  {
    for (int i = 0; i < n; ++i) {
      if (i <= skill.first || i >= skill.second) {
        nvs.pb(vs[i]);
      }
    }
    nps.clear();
    for (int i = 0; i < sz(ps); ++i) {
      if (ps[i] == skill) {
        continue;
      }
      if (!(skill.first < ps[i].first && ps[i].first < skill.second) &&
          !(skill.first < ps[i].second && ps[i].second < skill.second)) {
        int xs[2] = {ps[i].first, ps[i].second};
        for (int it = 0; it < 2; ++it) {
          if (xs[it] >= skill.second) {
            xs[it] -= skill.second - skill.first - 1;
          }
        }
        nps.pb(mp(xs[0], xs[1]));
      }
    }
    touse.pb(mp(nps, nvs));
  }
  for (int j = skill.second; j > skill.first; --j) {
    int it = sz(lefts[j]) - 1;
    if (j == skill.second) {
      while (it >= 0 && lefts[j][it] <= skill.first) {
        --it;
      }
    }
    if (it == -1) {
      continue;
    }
    int l = lefts[j][it], r = j;
    nvs.clear();
    for (int i = l; i <= r; ++i) {
      nvs.pb(vs[i]);
    }
    nps.clear();
    for (int k = r; k > l; --k) {
      for (int x : lefts[k]) {
        if (k < r || x > l) {
          nps.pb(mp(x - l, k - l));
        }
      }
    }
    touse.pb(mp(nps, nvs));
  }

  for (auto &cur : touse) {
    solve(col + 1, cur.second, cur.first);
  }
}

void solve() {
  vector<int> vs;
  for (int i = 0; i < n; ++i) {
    vs.pb(i);
  }
  solve(0, vs, ps);
  for (int i = 0; i <= sz(ps); ++i) {
    printf("%d%c", 1 + ans[i], " \n"[i == sz(ps)]);
  }
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>
#include <cassert>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <utility>
#include <cmath>
#include <bitset>
#include <climits>
#include <iomanip>
#include <fstream>
#include <unordered_set>
#include <unordered_map>
#include <cstdio>
#include <cstring>

using namespace std;

#define ll long long
#define N (ll)(1e6+3)
#define INF (ll)(1e18+1)
#define EPS (1e-9)
#define PI (3.14159265358979323846)
#define ld double
#define MOD (ll)(1e9+7)

vector<ll> v[N];
vector<bool> used[N];
vector<ll> regions[N];
vector<ll> g[N];
map<pair<ll, ll>, ll> ma;
ll cnt = -1;
ll color[N];

ll dfs(ll u, ll par, ll depth, ll tot) {
    ll sum = 0;
    ll maxch = 0;
    vector<ll> chs = vector<ll>(g[u].size(), 0);
    for (ll i = 0; i < g[u].size(); i++) {
        ll ch = g[u][i];
        if (ch == par || color[ch])
            continue;

        ll res = dfs(ch, u, depth, tot);
        if (res == -1)
            return -1;
        sum += res;
        maxch = max(maxch, res);
        chs[i] = res;
    }

    //check if centroid
    if (tot-sum-1 <= tot/2 && maxch <= tot/2) {
        color[u] = depth;
        for (ll i = 0; i < g[u].size(); i++) {
            ll ch = g[u][i];
            if (ch == par)
                chs[i] = tot-sum-1;
            if (!color[ch])
                dfs(ch, ch, depth+1, chs[i]);
        }
        return -1;
    }

    return sum+1;
}

bool comp(pair<ll, ll> a, pair<ll, ll> b) {
    return regions[a.first] < regions[b.first];
}

void solve() {
    ll n, m;
    cin >> n >> m;
    for (ll i = 0; i < m; i++) {
        ll a, b;
        cin >> a >> b;
        a--, b--;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    for (ll i = 0; i < n; i++) {
        v[i].push_back((i+1)%n);
        v[(i+1)%n].push_back(i);
    }
    for (ll i = 0; i < n; i++) {
        sort(v[i].begin(), v[i].end());
        used[i] = vector<bool>(v[i].size(), false);
    }

    for (ll i = 0; i < n; i++) {
        for (ll j = 0; j < v[i].size(); j++) {
            ll p = i;
            ll id = j;

            vector<ll> r;
            while (!used[p][id]) {
                r.push_back(p);
                used[p][id] = true;

                ll ind = v[p][id];
                ll new_id = lower_bound(v[ind].begin(), v[ind].end(), p) - v[ind].begin();
                new_id = (new_id + 1) % v[ind].size();
                p = ind;
                id = new_id;
            }

            if (r.size() == 0)
                continue;

            if (cnt == -1) {
                cnt++;
                continue;
            }

            for (ll k = 0; k < r.size(); k++) {
                ll x = r[k], y = r[(k+1)%r.size()];
                if (x > y)
                    swap(x, y);
                if (ma.find({x,y}) != ma.end()) {
                    g[cnt].push_back(ma[{x,y}]);
                    g[ma[{x,y}]].push_back(cnt);
                } else {
                    ma[{x,y}] = cnt;
                }
            }

            sort(r.begin(), r.end());
            reverse(r.begin(), r.end());
            regions[cnt++] = r;
        }
    }

//    for (ll i = 0; i < cnt; i++) {
//        for (ll j = 0; j < regions[i].size(); j++) {
//            cout << regions[i][j] << " ";
//        }
//        cout << endl;
//        for (ll j = 0; j < g[i].size(); j++) {
//            cout << g[i][j] << " ";
//        }
//        cout << endl;
//        cout << endl;
//    }
//

    dfs(0, 0, 1, cnt);

    vector<pair<ll,ll> > ans;
    for (ll i = 0; i < cnt; i++) {
        ans.push_back({i, color[i]});
    }
    sort(ans.begin(), ans.end(), comp);

    for (ll i = 0; i < ans.size(); i++) {
        cout << ans[i].second << " ";
    }
    cout << endl;
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    solve();
}


#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>
#include <cassert>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <utility>
#include <cmath>
#include <bitset>
#include <climits>
#include <iomanip>
#include <fstream>
#include <unordered_set>
#include <unordered_map>
#include <cstdio>
#include <cstring>

using namespace std;

#define ll long long
#define N (ll)(1e6+3)
#define INF (ll)(1e18+1)
#define EPS (1e-9)
#define PI (3.14159265358979323846)
#define ld double
#define MOD (ll)(1e9+7)

vector<ll> v[N];
vector<bool> used[N];
vector<ll> regions[N];
vector<ll> g[N];
map<pair<ll, ll>, ll> ma;
ll cnt = -1;
ll color[N];

ll dfs(ll u, ll par, ll depth, ll tot) {
    ll sum = 0;
    ll maxch = 0;
    vector<ll> chs = vector<ll>(g[u].size(), 0);
    for (ll i = 0; i < g[u].size(); i++) {
        ll ch = g[u][i];
        if (ch == par || color[ch])
            continue;

        ll res = dfs(ch, u, depth, tot);
        if (res == -1)
            return -1;
        sum += res;
        maxch = max(maxch, res);
        chs[i] = res;
    }

    //check if centroid
    if (tot-sum-1 <= tot/2 && maxch <= tot/2) {
        color[u] = depth;
        for (ll i = 0; i < g[u].size(); i++) {
            ll ch = g[u][i];
            if (!color[ch])
                dfs(ch, ch, depth+1, chs[i]);
        }
        return -1;
    }

    return sum+1;
}

bool comp(pair<ll, ll> a, pair<ll, ll> b) {
    return regions[a.first] < regions[b.first];
}

void solve() {
    ll n, m;
    cin >> n >> m;
    for (ll i = 0; i < m; i++) {
        ll a, b;
        cin >> a >> b;
        a--, b--;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    for (ll i = 0; i < n; i++) {
        v[i].push_back((i+1)%n);
        v[(i+1)%n].push_back(i);
    }
    for (ll i = 0; i < n; i++) {
        sort(v[i].begin(), v[i].end());
        used[i] = vector<bool>(v[i].size(), false);
    }

    for (ll i = 0; i < n; i++) {
        for (ll j = 0; j < v[i].size(); j++) {
            ll p = i;
            ll id = j;

            vector<ll> r;
            while (!used[p][id]) {
                r.push_back(p);
                used[p][id] = true;

                ll ind = v[p][id];
                ll new_id = lower_bound(v[ind].begin(), v[ind].end(), p) - v[ind].begin();
                new_id = (new_id + 1) % v[ind].size();
                p = ind;
                id = new_id;
            }

            if (r.size() == 0)
                continue;

            if (cnt == -1) {
                cnt++;
                continue;
            }

            for (ll k = 0; k < r.size(); k++) {
                ll x = r[k], y = r[(k+1)%r.size()];
                if (x > y)
                    swap(x, y);
                if (ma.find({x,y}) != ma.end()) {
                    g[cnt].push_back(ma[{x,y}]);
                    g[ma[{x,y}]].push_back(cnt);
                } else {
                    ma[{x,y}] = cnt;
                }
            }

            sort(r.begin(), r.end());
            reverse(r.begin(), r.end());
            regions[cnt++] = r;
        }
    }

//    for (ll i = 0; i < cnt; i++) {
//        for (ll j = 0; j < regions[i].size(); j++) {
//            cout << regions[i][j] << " ";
//        }
//        cout << endl;
//        for (ll j = 0; j < g[i].size(); j++) {
//            cout << g[i][j] << " ";
//        }
//        cout << endl;
//        cout << endl;
//    }
//

    dfs(0, 0, 1, cnt);

    vector<pair<ll,ll> > ans;
    for (ll i = 0; i < cnt; i++) {
        ans.push_back({i, color[i]});
    }
    sort(ans.begin(), ans.end(), comp);

    for (ll i = 0; i < ans.size(); i++) {
        cout << ans[i].second << " ";
    }
    cout << endl;
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    solve();
}


#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

#define mp make_pair
#define pb push_back
#define sz(s) ((int) ((s).size()))

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

typedef long long ll;
typedef long double ld;

const int inf = (int) 1.01e9;
const ld eps = 1e-11;
const ld pi = acos(-1.0L);

mt19937 mrand(random_device{} ());
int rnd(int x) {
  return mrand() % x;
}

const int mod = (int) 1e9 + 7;

void add(int & x, int y) {
  if ((x += y) >= mod) {
    x -= mod;
  }
}

int sum(int x, int y) {
  add(x, y);
  return x;
}

int mult(int x, int y) {
  return (ll) x * y % mod;
}

int power(int x, ll p) {
  int res = 1;
  while (p) {
    if (p & 1) {
      res = mult(res, x);
    }
    x = mult(x, x);
    p >>= 1;
  }
  return res;
}

int inv(int x) {
  return power(x, mod - 2);
}

void precalc() {
}

const int maxn = 5e5 + 100;

int from[maxn], to[maxn], cnte;
vector<vector<int> > in;

void adde(int u, int v) {
  from[cnte] = u;
  to[cnte] = v;
  in[v].pb(cnte);
  cnte++;
  from[cnte] = v;
  to[cnte] = u;
  in[u].pb(cnte);
  cnte++;
}

int n, m;

bool read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return false;
  }
  cnte = 0;
  in.clear();
  in.resize(n);
  for (int i = 0; i < n; i++) {
    adde(i, (i + 1) % n);
  }
  for (int i = 0; i < m; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    u--, v--;
    adde(u, v);
  }
  return true;
}

#define rank mrank

int par[maxn], rank[maxn];

int getpar(int v) {
  if (par[v] == v) {
    return v;
  } else {
    return par[v] = getpar(par[v]);
  }
}

void myUnion(int a, int b) {
  a = getpar(a);
  b = getpar(b);
  if (a == b) {
    return;
  }
  if (rank[a] == rank[b]) {
    rank[a]++;
  }
  if (rank[a] < rank[b]) {
    swap(a, b);
  }
  par[b] = a;
}

struct mycomp {
  int center;

  mycomp(int center = 0) : center(center) {}

  bool operator() (const int & a, const int & b) const {
    int c = ((center - from[a]) % n + n) % n;
    int d = ((center - from[b]) % n + n) % n;
    return c < d;
  }
};

int used[maxn];

vector<vector<int> > tree;
int ans[maxn], cnt[maxn];

void getcnt(int v, int par) {
  cnt[v] = 1;
  for (auto to : tree[v]) {
    if (to == par) {
      continue;
    }
    if (used[to]) {
      continue;
    }
    getcnt(to, v);
    cnt[v] += cnt[to];
  }
}

void solve(int v, int depth = 0) {
  getcnt(v, -1);
  int all = cnt[v];
  while (true) {
    int mxi = -1;
    for (auto to : tree[v]) {
      if (used[to]) {
        continue;
      }
      if (cnt[to] < cnt[v] && (mxi == -1 || cnt[mxi] < cnt[to])) {
        mxi = to;
      }
    }
    if (mxi != -1 && cnt[mxi] * 2 > all) {
      v = mxi;
    } else {
      break;
    }
  }
  used[v] = 1;
  ans[v] = depth;
  for (auto to : tree[v]) {
    if (!used[to]) {
      solve(to, depth + 1);
    }
  }
}

void solve() {
  for (int i = 0; i < cnte; i++) {
    par[i] = i;
    rank[i] = 0;
  }

  for (int i = 0; i < n; i++) {
    sort(in[i].begin(), in[i].end(), mycomp(i));
    for (int j = 0; j + 1 < sz(in[i]); j++) {
      int a = in[i][j];
      int b = in[i][j + 1] ^ 1;
      myUnion(a, b);
    }
  }
  memset(used, 0, sizeof(used));
  tree.clear();
  tree.resize(2 * (n + m));
  for (int i = 2 * n; i < 2 * (n + m); i += 2) {
    int u = getpar(i), v = getpar(i ^ 1);
    tree[u].pb(v);
    tree[v].pb(u);
    //eprintf("%d %d\n", u, v);
  }
  solve(in[0][0]);
  memset(used, 0, sizeof(used));
  vector<int> toprint;
  for (int i = n - 1; i >= 0; i--) {
    for (int j = 0; j + 1 < sz(in[i]); j++) {
      int a = getpar(in[i][j]);
      if (used[a]) {
        continue;
      }
      toprint.pb(ans[a] + 1);
      used[a] = 1;
    }
  }
  reverse(toprint.begin(), toprint.end());
  assert(sz(toprint));
  for (int i = 0; i < sz(toprint); i++) {
    printf("%d%c", toprint[i], " \n"[i == sz(toprint) - 1]);
  }
}

int main() {
  precalc();
#ifdef DEBUG
  assert(freopen("text.in", "r", stdin));
  assert(freopen("text.out", "w", stdout));
#endif

  while (read()) {
    solve();
#ifdef DEBUG
    eprintf("Time: %.3f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#include <bits/stdc++.h>

#define debug(x) cout << #x" = " << x;

#define st first
#define nd second

using namespace std;
using namespace placeholders;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;

const int MAXN = 1E5 + 10;

int n, m;
vector<int> B[MAXN], mark[MAXN];
vector<int> E[MAXN];

int tot, id[MAXN];
vector<int> seq[MAXN];

int color[MAXN];

int totSize, cent, centSize;
int size[MAXN];

void getCentroid(int u, int pre)
{
    size[u] = 1;
    int vs = 0;
    for (int v, i = 0; i < E[u].size(); ++i) {
        if ((v = E[u][i]) == pre || color[v])
            continue;
        getCentroid(v, u);
        size[u] += size[v];
        vs = max(vs, size[v]);
    }
    vs = max(vs, totSize - size[u]);
    if (centSize > vs)
        cent = u, centSize = vs;
}

void solve(int u, int tot, int dep)
{
    totSize = centSize = tot, cent = u;
    getCentroid(u, -1);
    color[u = cent] = dep;

    for (int v, i = 0; i < E[u].size(); ++i)
        if (!color[v = E[u][i]])
            solve(v, size[v] < size[u] ? size[v] : tot - size[u], dep + 1);
}

int main()
{
    scanf("%d%d", &n, &m);
    if (m == 0) {
        puts("1");
        return 0;
    }

    for (int i = 1; i <= n; ++i) {
        B[i].push_back(i % n + 1);
        B[i % n + 1].push_back(i);
    }
    for(int u, v, i = 1; i <= m; i++) {
        scanf("%d%d", &u, &v);
        B[u].push_back(v);
        B[v].push_back(u);
    }
    for (int i = 1; i <= n; ++i) {
        sort(B[i].begin(), B[i].end());
        mark[i] = vector<int>(B[i].size(), -1);
    }

    tot = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < B[i].size(); ++j) {
            if (mark[i][j] > -1)
                continue;

            int u = i, t = j;
            int v = B[u][t];
            do {
                seq[tot].push_back(u);
//				printf("%d %d\n", u, v);

                t = (lower_bound(B[v].begin(), B[v].end(), u) - B[v].begin() + 1) % B[v].size();
                u = v, v = B[v][t];
                mark[u][t] = tot;
            }
            while (u != i);
            sort(seq[tot].begin(), seq[tot].end(), greater<int>());
//			printf("%d\n", tot);
            ++tot;
        }
    }

    vector<int> lst(tot);
    for (int i = 0; i < tot; ++i)
        lst[i] = i;
    sort(lst.begin(), lst.end(), [](int l, int r) {
        return seq[l] < seq[r];
    });
    for (int i = 0; i < tot; ++i)
        id[lst[i]] = i;

    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < B[i].size(); ++j) {
            int k = B[i][j];
            int l = lower_bound(B[k].begin(), B[k].end(), i) - B[k].begin();
            if (seq[mark[i][j]].size() == n || seq[mark[k][l]].size() == n)
                continue;
            int u = id[mark[i][j]], v = id[mark[k][l]];
            E[u].push_back(v);
        }
    }

    solve(0, tot - 1, 1);
    for (int i = 0; i < tot - 1; ++i)
        printf("%d%c", color[i], "\n "[i < tot - 2]);
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int maxn = 400005;

int n,m;

namespace Tree
{
	vector<int> inc[maxn];
	vector<int> lk[maxn];
	int ord[maxn],co,col[maxn];
	bool out[maxn],wal[maxn];

	void insert(int p)
	{
		inc[co].push_back(p);
	}

	void link(int u,int v)
	{
		if (out[u] || out[v]) return;
		lk[u].push_back(v);
	}

	bool cmp(int a,int b)
	{
		for(int i = 0,l = min(inc[a].size(),inc[b].size());i < l;i ++)
			if (inc[a][i] > inc[b][i]) return 0; else
				if (inc[a][i] < inc[b][i]) return 1;
		return inc[a].size() < inc[b].size();
	}

	int bfs(int s)
	{
		static int que[maxn],fa[maxn],siz[maxn];
		int fi = 1,en = 1;
		que[1] = s,fa[s] = 0;
		for(;fi <= en;fi ++)
		{
			int u = que[fi];
			for(int i = 0;i < lk[u].size();i ++)
				if (!wal[lk[u][i]] && fa[u] != lk[u][i]) que[++ en] = lk[u][i],fa[lk[u][i]] = u;
		}
		for(int i = en;i;i --)
		{
			int u = que[i];
			siz[u] = 1;
			bool ok = 1;
			for(int j = 0;j < lk[u].size();j ++)
				if (!wal[lk[u][j]] && fa[lk[u][j]] == u) siz[u] += siz[lk[u][j]],ok &= (siz[lk[u][j]] <= en / 2);
			ok &= ((en - siz[u]) <= en / 2);
			if (ok) return u;
		}
	}

	void dfs(int now,int dep)
	{
		now = bfs(now);
		col[now] = dep;
		wal[now] = 1;
		for(int i = 0;i < lk[now].size();i ++)
			if (!wal[lk[now][i]]) dfs(lk[now][i],dep + 1);
	}

	void work()
	{
		for(int i = 1;i <= co;i ++) if (!out[i]) {dfs(i,1);break;}
		for(int i = 1;i <= co;i ++) ord[i] = i,sort(inc[i].begin(),inc[i].end()),reverse(inc[i].begin(),inc[i].end());
		sort(ord + 1,ord + co + 1,cmp);
		for(int i = 1;i <= co;i ++)
			if (out[ord[i]]) continue; else printf("%d ", col[ord[i]]);
	}
}

namespace Planar
{
	vector<int> lk[maxn];
	bool wal[maxn * 2];
	int go[maxn * 2],pos[maxn * 2],bel[maxn * 2],tot,O;

	bool cmp(int a,int b)
	{
		a = go[a],b = go[b];
		a = (a - O + n - 1) % n + 1,b = (b - O + n - 1) % n + 1;
		return a < b;
	}

	void link(int u,int v)
	{
		lk[u].push_back(++ tot),go[tot] = v;
		lk[v].push_back(++ tot),go[tot] = u;
	}

	void dfs(int p)
	{
		wal[p] = 1;
		bel[p] = Tree::co;
		int v = go[p];
		if (v != O) Tree::insert(v); else return;
		dfs(lk[v][(pos[p ^ 1] - 1 + lk[v].size()) % lk[v].size()]);
	}

	void work()
	{
		for(int i = 1;i <= n;i ++) link(i, i % n + 1);
		for(int i = 1;i <= n;i ++)
		{
			O = i,sort(lk[i].begin(),lk[i].end(),cmp);
			for(int j = 0;j < lk[i].size();j ++) pos[lk[i][j]] = j;
		}
		bool outer = 0;
		for(int i = 1;i <= n;i ++)
			for(int j = 0;j < lk[i].size();j ++)
				if (!wal[lk[i][j]])
				{
					Tree::co ++;
					O = i;
					Tree::insert(i);
					dfs(lk[i][j]);
					if (!outer && Tree::inc[Tree::co].size() == n)
						outer = 1,Tree::out[Tree::co] = 1;
				}
		for(int i = 1;i <= tot;i ++)
			Tree::link(bel[i],bel[i ^ 1]);
	}
}

int main()
{
	scanf("%d%d", &n, &m);
	Planar::tot = 1;
	for(int i = 1,a,b;i <= m;i ++)
		scanf("%d%d", &a, &b),Planar::link(a,b);
	Planar::work();
	Tree::work();
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int maxn = 400005;

int n,m;

namespace Tree
{
	vector<int> inc[maxn];
	vector<int> lk[maxn];
	int ord[maxn],co,col[maxn];
	bool out[maxn],wal[maxn];

	void insert(int p)
	{
		inc[co].push_back(p);
	}

	void link(int u,int v)
	{
		if (out[u] || out[v]) return;
		lk[u].push_back(v);
	}

	bool cmp(int a,int b)
	{
		for(int i = 0,l = min(inc[a].size(),inc[b].size());i < l;i ++)
			if (inc[a][i] > inc[b][i]) return 0; else
				if (inc[a][i] < inc[b][i]) return 1;
		return inc[a].size() < inc[b].size();
	}

	int bfs(int s)
	{
		static int que[maxn],fa[maxn],siz[maxn];
		int fi = 1,en = 1;
		que[1] = s,fa[s] = 0;
		for(;fi <= en;fi ++)
		{
			int u = que[fi];
			for(int i = 0;i < lk[u].size();i ++)
				if (!wal[lk[u][i]] && fa[u] != lk[u][i]) que[++ en] = lk[u][i],fa[lk[u][i]] = u;
		}
		for(int i = en;i;i --)
		{
			int u = que[i];
			siz[u] = 1;
			bool ok = 1;
			for(int j = 0;j < lk[u].size();j ++)
				if (!wal[lk[u][j]] && fa[lk[u][j]] == u) siz[u] += siz[lk[u][j]],ok &= (siz[lk[u][j]] <= en / 2);
			ok &= ((en - siz[u]) <= en / 2);
			if (ok) return u;
		}
	}

	void dfs(int now,int dep)
	{
		now = bfs(now);
		col[now] = dep;
		wal[now] = 1;
		for(int i = 0;i < lk[now].size();i ++)
			if (!wal[lk[now][i]]) dfs(lk[now][i],dep + 1);
	}

	void work()
	{
		for(int i = 1;i <= co;i ++) if (!out[i]) {dfs(i,1);break;}
		for(int i = 1;i <= co;i ++) ord[i] = i,sort(inc[i].begin(),inc[i].end()),reverse(inc[i].begin(),inc[i].end());
		sort(ord + 1,ord + co + 1,cmp);
		for(int i = 1;i <= co;i ++)
			if (out[ord[i]]) continue; else printf("%d ", col[ord[i]]);
	}
}

namespace Planar
{
	vector<int> lk[maxn];
	bool wal[maxn * 2];
	int go[maxn * 2],pos[maxn * 2],bel[maxn * 2],tot,O;

	bool cmp(int a,int b)
	{
		a = go[a],b = go[b];
		a = (a - O + n - 1) % n + 1,b = (b - O + n - 1) % n + 1;
		return a < b;
	}

	void link(int u,int v)
	{
		lk[u].push_back(++ tot),go[tot] = v;
		lk[v].push_back(++ tot),go[tot] = u;
	}

	void dfs(int p)
	{
		wal[p] = 1;
		bel[p] = Tree::co;
		int v = go[p];
		if (v != O) Tree::insert(v); else return;
		dfs(lk[v][(pos[p ^ 1] - 1 + lk[v].size()) % lk[v].size()]);
	}

	void work()
	{
		for(int i = 1;i <= n;i ++) link(i, i % n + 1);
		for(int i = 1;i <= n;i ++)
		{
			O = i,sort(lk[i].begin(),lk[i].end(),cmp);
			for(int j = 0;j < lk[i].size();j ++) pos[lk[i][j]] = j;
		}
		bool outer = 0;
		for(int i = 1;i <= n;i ++)
			for(int j = 0;j < lk[i].size();j ++)
				if (!wal[lk[i][j]])
				{
					Tree::co ++;
					O = i;
					Tree::insert(i);
					dfs(lk[i][j]);
					if (!outer && Tree::inc[Tree::co].size() == n)
						Tree::out[Tree::co] = 1;
				}
		for(int i = 1;i <= tot;i ++)
			Tree::link(bel[i],bel[i ^ 1]);
	}
}

int main()
{
	scanf("%d%d", &n, &m);
	Planar::tot = 1;
	for(int i = 1,a,b;i <= m;i ++)
		scanf("%d%d", &a, &b),Planar::link(a,b);
	Planar::work();
	Tree::work();
	return 0;
}


#include<bits/stdc++.h>
#define y second
#define x first

using namespace std;
using pii = pair<int, int>;
using ppi = pair<pii, int>;
const int NN = 101010;

multiset<int> s;
multiset<int> :: iterator iit;

set<int> adj[NN];
set<int> :: iterator it;

int st[NN], ed[NN], B[NN], n;
void add(int u, int x) {
	for(; u <= n; u += u & -u) B[u] += x;
}
int calc(int u) {int ans = 0;
	for(; u; u ^= u & -u) ans += B[u];
	return ans;
}

int one[NN], two[NN], col[NN];
ppi p[NN];

void update(int u, int x) {
	if(x > two[u]) {
		two[u] = x;
		if(two[u] > one[u]) swap(one[u], two[u]);
	}
}
void update(int u, int L, int R) {
	if(L == R) update(u, L);
	else update(u, R - 1), update(u, R);
}

void solve(int L, int R, int c) {
	int md = L + R >> 1; col[md] = c;
	if(L < md) solve(L, md - 1, c + 1);
	if(md < R) solve(md + 1, R, c + 1);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int m; scanf("%d %d", &n, &m);
	if(m < 20) {
		for(int i = 1; i <= m + 1; i++) printf("%d ", i);
		return 0;
	}

	for(int i = 1; i <= m; i++) {
		scanf("%d %d", st + i, ed + i);
		if(st[i] > ed[i]) swap(st[i], ed[i]);

		add(st[i], 1), s.insert(st[i]);
		add(ed[i], 1), s.insert(ed[i]);
		adj[st[i]].insert(ed[i]);
		adj[ed[i]].insert(st[i]);
	}
	int L, R, x, y, N = 1;
	for(int i = 1; i <= m; i++) {
		if(calc(ed[i] - 1) - calc(st[i]) == 0) {
			update(0, L = st[i], R = ed[i]);
			break;
		}
	}
	for(; ; N++, L = x, R = y) {
		add(L, -1), s.erase(s.find(L));
		add(R, -1), s.erase(s.find(R));
		adj[L].erase(R), adj[R].erase(L);
		if(s.empty()) {
			if(L > R) update(N, R, L);
			else update(N, 1, L), update(N, R, n);
			N++; break;
		}
		iit = s.upper_bound(L);
		if(iit == s.begin()) {
			x = *s.rbegin();
			update(N, 1, L), update(N, x, n);
			y = *adj[x].begin();
			update(N, R, y);
		}
		else {
			x = *--iit, update(N, x, L);
			it = adj[x].upper_bound(x);
			if(it == adj[x].end()) {
				y = *adj[x].begin();
				update(N, R, n), update(N, 1, y);
			}
			else {
				y = *it, update(N, R, y);
			}
		}
	}
	solve(0, N - 1, 1);
	for(int i = 0; i < N; i++) p[i] = {{one[i], two[i]}, col[i]};
	sort(p, p + N);
	reverse(p, p + N);
	for(int i = 0; i < N; i++) printf("%d ", p[i].y);
}


#include<bits/stdc++.h>

using namespace std;

using INT = long long;

#define NN 101000

int A[NN], B[NN], id[NN];
vector<int> rg[NN];
int nn = 0;
map<pair<int, int>, int> mp;
vector<int> adj[NN];
int ans[NN];

int smax(int &u, int v) {
	if(u < v) swap(u, v);
}

int update(int u, int v, int id) {
	if(u > v) swap(u, v);
	if(mp.count({u, v})) {
		int x = mp[{u, v}];
		adj[id].push_back(x);
		adj[x].push_back(id);
	} else mp[{u, v}] = id;
}

int qf, qb, q[NN], sz[NN], fa[NN], vst[NN];

int find_root(int u){
	qf=qb=0;
	q[qb++]=u; fa[u]=0;
	while(qf<qb){
		u=q[qf++];
		for(int v : adj[u]) {
			if(v==fa[u] || vst[v]) continue;
			fa[v]=u;
			q[qb++]=v;
		}
	}
	nn=qb;
	for(int i=nn; i--; ){
		sz[u=q[i]]=1;
		int mx=0;
		for(int v : adj[u]) {
			if(v==fa[u] || vst[v]) continue;
			smax(mx, sz[v]);
			sz[u]+=sz[v];
		}
		if(mx*2<=nn && sz[u]*2>=nn) return u;
	}
}

void solve(int u, int mx = 1){
	u=find_root(u);

	vst[u]=1; ans[u] = mx;

	for(int v : adj[u]) {
		if(!vst[v]) solve(v, mx+1);
	}

	return ;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int n, m;
	cin >> n >> m;
	for(int i=1; i<=m; i++) {
		scanf("%d %d", &A[i], &B[i]);
		if(A[i] > B[i]) swap(A[i], B[i]);
		id[i] = i;
	}

	sort(id+1, id+m+1, [&] (int u, int v) {
		if(A[u] != A[v]) return A[u] < A[v];
		return B[u] < B[v];
	});

	vector<int> buf;
	int pos = 0;
	for(int i=1; i<=m; i++) {
		while(pos < B[id[i]]) {
			pos++;
			buf.push_back(pos);
		} nn++;
		while(buf.back() != A[id[i]]) {
			rg[nn].push_back(buf.back());
			buf.pop_back();
		}
		rg[nn].push_back(A[id[i]]); buf.push_back(B[id[i]]);
	}

	while(pos < n) {
		pos++;
		buf.push_back(pos);
	} nn++;
	for(auto u : buf) {
		rg[nn].push_back(u);
	}

	for(int i=1; i<=nn; i++) {
		sort(rg[i].begin(), rg[i].end());
		reverse(rg[i].begin(), rg[i].end());
		id[i] = i;
	}

	sort(id+1, id+nn+1, [&] (int u, int v) {
		for(int i=0; i<rg[u].size(); i++) {
			if(rg[u][i] != rg[v][i]) {
				return rg[u][i] < rg[v][i];
			}
		}
	});

	for(int i=1; i<=nn; i++) {
		int u = id[i];
		for(int j=1; j<rg[u].size(); j++) {
			update(rg[u][j-1], rg[u][j], i);
		}
		update(rg[u].back(), rg[u][0], i);
	}

	int N = nn;
	solve(1);

	for(int i=1; i<=N; i++) {
		printf("%d ", ans[i]);
	} puts("");

	return 0;
}


#include <bits/stdc++.h>
#define x first
#define y second

using namespace std;
typedef pair<int, int> pii;

#define NN 100010
vector<int> vec[NN];
int E, nxt[NN<<1], head[NN], to[NN<<1];
int rk[NN], ans[NN], qv[NN];
pii cov[NN];
map<pii, int> mp;

void add(int u, int v) {
	nxt[E] = head[u]; to[E] = v; head[u] = E++;
	nxt[E] = head[v]; to[E] = u; head[v] = E++;
}

int nn, qf, qb, q[NN], sz[NN], fa[NN], vst[NN];

int find_root(int u){
	qf = qb = 0;
	q[qb++] = u; fa[u] = 0;
	while(qf<qb){
		u = q[qf++];
		for(int i=head[u]; ~i; i=nxt[i]){
			int v = to[i];
			if(v == fa[u] || vst[v]) continue;
			fa[v] = u;
			q[qb++] = v;
		}
	}
	nn = qb;
	for(int i=nn; i--; ){
		sz[u=q[i]] = 1;
		int mx = 0;
		for(int j=head[u]; ~j; j=nxt[j]){
			int v = to[j];
			if(v == fa[u] || vst[v]) continue;
			mx = max(mx, sz[v]);
			sz[u] += sz[v];
		}
		if(mx*2 <= nn && sz[u] * 2 >= nn) return u;
	}
}

void solve(int u, int col){
	u = find_root(u);
	ans[u] = col;
	vst[u] = 1;
	for(int e=head[u]; ~e; e=nxt[e]) {
		int v = to[e];
		if(!vst[v]) solve(v, col + 1);
	}
	return ;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	memset(head, -1, sizeof head);

	int n, m;
	scanf("%d %d", &n, &m);
	while(m--){
		int x, y;
		scanf("%d %d", &x, &y);
		if(x > y) swap(x, y);
		vec[y].push_back(x);
	}

	int k = 0;
	for(int j=1; j<=n; j++){
		sort(vec[j].begin(), vec[j].end(), [&] (int x, int y){
			return x > y;
		});
		for(int i : vec[j]){
			k++;
			mp[{i, j}] = k;
			if(mp.count({qv[nn], j})) add(k, mp[{qv[nn], j}]);
			cov[k] = {j, qv[nn]};
			while(qv[nn] > i){
				if(mp.count({qv[nn-1], qv[nn]})){
					add(k, mp[{qv[nn-1], qv[nn]}]);
				}
				nn--;
			}
		}
		qv[++nn] = j;
	}
	k++;
	for(int i=1; i<=nn; i++){
		int x = qv[i], y = qv[i+1];
		if(cov[k].x < x){
			cov[k].y = cov[k].x;
			cov[k].x = x;
		}
		else{
			if(cov[k].y < x) cov[k].y = x;
		}
		if(i == nn) y = qv[1];
		if(x > y) swap(x, y);
		if(mp.count({x, y})){
			add(k, mp[{x, y}]);
		}
	}

	for(int i=1; i<=k; i++) rk[i] = i;
	sort(rk + 1, rk + k + 1, [&] (int i, int j){
		if(cov[i].x != cov[j].x) return cov[i].x < cov[j].x;
		return cov[i].y < cov[j].y;
	});

	solve(1, 1);
	for(int i=1; i<=k; i++){
		printf("%d ", ans[rk[i]]);
	}
}


#include <bits/stdc++.h>
#define x first
#define y second

using namespace std;
typedef pair<int, int> pii;

#define NN 100010
vector<int> vec[NN];
int E, nxt[NN<<1], head[NN], to[NN<<1];
int rk[NN], ans[NN], qv[NN];
pii cov[NN];
map<pii, int> mp;

void add(int u, int v) {
	nxt[E] = head[u]; to[E] = v; head[u] = E++;
	nxt[E] = head[v]; to[E] = u; head[v] = E++;
}

int nn, qf, qb, q[NN], sz[NN], fa[NN], vst[NN];

int find_root(int u){
	qf = qb = 0;
	q[qb++] = u; fa[u] = 0;
	while(qf<qb){
		u = q[qf++];
		for(int i=head[u]; ~i; i=nxt[i]){
			int v = to[i];
			if(v == fa[u] || vst[v]) continue;
			fa[v] = u;
			q[qb++] = v;
		}
	}
	nn = qb;
	for(int i=nn; i--; ){
		sz[u=q[i]] = 1;
		int mx = 0;
		for(int j=head[u]; ~j; j=nxt[j]){
			int v = to[j];
			if(v == fa[u] || vst[v]) continue;
			mx = max(mx, sz[v]);
			sz[u] += sz[v];
		}
		if(mx*2 <= nn && sz[u] * 2 >= nn) return u;
	}
}

void solve(int u, int col){
	u = find_root(u);
	ans[u] = col;
	vst[u] = 1;
	for(int e=head[u]; ~e; e=nxt[e]) {
		int v = to[e];
		if(!vst[v]) solve(v, col + 1);
	}
	return ;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	memset(head, -1, sizeof head);
	int n, m;
	scanf("%d %d", &n, &m);
	while(m--){
		int x, y;
		scanf("%d %d", &x, &y);
		if(x > y) swap(x, y);
		vec[y].push_back(x);
	}
	int k = 0;
	for(int j=1; j<=n; j++){
		sort(vec[j].begin(), vec[j].end(), [&] (int x, int y){
			return x > y;
		});
		for(int i : vec[j]){
			k++;
			mp[{i, j}] = k;
			if(mp.count({qv[nn], j})) add(k, mp[{qv[nn], j}]);
			cov[k] = {j, qv[nn]};
			while(qv[nn] > i){
				if(mp.count({qv[nn-1], qv[nn]})){
					add(k, mp[{qv[nn-1], qv[nn]}]);
				}
				nn--;
			}
		}
		qv[++nn] = j;
	}
	k++;
	for(int i=1; i<=nn; i++){
		int x = qv[i], y = qv[i+1];
		if(cov[k].x < x){
			cov[k].y = cov[k].x;
			cov[k].x = x;
		}
		else{
			if(cov[k].y < x) cov[k].y = x;
		}
		if(i == n) y = qv[1];
		if(x > y) swap(x, y);
		if(mp.count({x, y})){
			add(k, mp[{x, y}]);
		}
	}

	for(int i=1; i<=k; i++){
		rk[i] = i;
	}

	sort(rk + 1, rk + k + 1, [&] (int i, int j){
		if(cov[i].x != cov[j].x) return cov[i].x < cov[j].x;
		return cov[i].y < cov[j].y;
	});

	solve(1, 1);
	for(int i=1; i<=k; i++){
		printf("%d ", ans[rk[i]]);
	}
}


#include<bits/stdc++.h>
#define y second
#define x first

using namespace std;
using pii = pair<int, int>;
using ppi = pair<pii, int>;
const int NN = 101010;

multiset<int> s;
multiset<int> :: iterator iit;

set<int> adj[NN];
set<int> :: iterator it;

int st[NN], ed[NN], B[NN], n;
void add(int u, int x) {
	for(; u <= n; u += u & -u) B[u] += x;
}
int calc(int u) {int ans = 0;
	for(; u; u ^= u & -u) ans += B[u];
	return ans;
}

int one[NN], two[NN], col[NN];
ppi p[NN];

void update(int u, int x) {
	if(x > two[u]) {
		two[u] = x;
		if(two[u] > one[u]) swap(one[u], two[u]);
	}
}
void update(int u, int L, int R) {
	if(L == R) update(u, L);
	else update(u, R - 1), update(u, R);
}

void solve(int L, int R, int c) {
	int md = L + R >> 1; col[md] = c;
	if(L < md) solve(L, md - 1, c + 1);
	if(md < R) solve(md + 1, R, c + 1);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int m; scanf("%d %d", &n, &m);
	if(m < 20) {
		for(int i = 1; i <= m + 1; i++) printf("%d ", i);
		return 0;
	}

	for(int i = 1; i <= m; i++) {
		scanf("%d %d", st + i, ed + i);
		if(st[i] > ed[i]) swap(st[i], ed[i]);

		add(st[i], 1), s.insert(st[i]);
		add(ed[i], 1), s.insert(ed[i]);
		adj[st[i]].insert(ed[i]);
		adj[ed[i]].insert(st[i]);
	}
	int L, R, x, y, N = 1;
	for(int i = 1; i <= m; i++) {
		if(calc(ed[i] - 1) - calc(st[i]) == 0) {
			update(0, L = st[i], R = ed[i]);
			break;
		}
	}
	for(; ; N++, L = x, R = y) {
		add(L, -1), s.erase(s.find(L));
		add(R, -1), s.erase(s.find(R));
		adj[L].erase(R), adj[R].erase(L);
		if(s.empty()) {
			if(L > R) update(N, R, L);
			else update(N, 1, L), update(N, R, n);
			N++; break;
		}
		iit = s.upper_bound(L);
		if(iit == s.begin()) {
			x = *s.rbegin();
			update(N, 1, L), update(N, x, n);
			y = *adj[x].begin();
			update(N, R, y);
		}
		else {
			x = *--iit, update(N, x, L);
			it = adj[x].upper_bound(x);
			if(it == adj[x].end()) {
				y = *adj[x].begin();
				update(N, R, n), update(N, 1, y);
			}
			else {
				y = *it, update(N, R, y);
			}
		}
	}
	solve(0, N - 1, 1);
	for(int i = 0; i < N; i++) p[i] = {{one[i], two[i]}, col[i]};
	sort(p, p + N);
	for(int i = 0; i < N; i++) printf("%d ", p[i].y);
}


#include<bits/stdc++.h>
#define y second
#define x first

using namespace std;
using pii = pair<int, int>;
using ppi = pair<pii, int>;
const int NN = 101010;

multiset<int> s;
multiset<int> :: iterator iit;

set<int> adj[NN];
set<int> :: iterator it;

int st[NN], ed[NN], B[NN], n;
void add(int u, int x) {
	for(; u <= n; u += u & -u) B[u] += x;
}
int calc(int u) {int ans = 0;
	for(; u; u ^= u & -u) ans += B[u];
	return ans;
}

int one[NN], two[NN], col[NN];
ppi p[NN];

void update(int u, int x) {
	if(x > two[u]) {
		two[u] = x;
		if(two[u] > one[u]) swap(one[u], two[u]);
	}
}
void update(int u, int L, int R) {
	if(L == R) update(u, L);
	else update(u, R - 1), update(u, R);
}

void solve(int L, int R, int c) {
	int md = L + R >> 1; col[md] = c;
	if(L < md) solve(L, md - 1, c + 1);
	if(md < R) solve(md + 1, R, c + 1);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int m; scanf("%d %d", &n, &m);
	if(!m) puts("1"), exit(0);
	for(int i = 1; i <= m; i++) {
		scanf("%d %d", st + i, ed + i);
		if(st[i] > ed[i]) swap(st[i], ed[i]);

		add(st[i], 1), s.insert(st[i]);
		add(ed[i], 1), s.insert(ed[i]);
		adj[st[i]].insert(ed[i]);
		adj[ed[i]].insert(st[i]);
	}
	int L, R, x, y, N = 1;
	for(int i = 1; i <= m; i++) {
		if(calc(ed[i] - 1) - calc(st[i]) == 0) {
			update(0, L = st[i], R = ed[i]);
			break;
		}
	}
	for(; ; N++, L = x, R = y) {
		add(L, -1), s.erase(s.find(L));
		add(R, -1), s.erase(s.find(R));
		adj[L].erase(R), adj[R].erase(L);
		if(s.empty()) {
			if(L > R) update(N, R, L);
			else update(N, 1, L), update(N, R, n);
			N++; break;
		}
		iit = s.upper_bound(L);
		if(iit == s.begin()) {
			x = *s.rbegin();
			update(N, 1, L), update(N, x, n);
			y = *adj[x].begin();
			update(N, R, y);
		}
		else {
			x = *--iit, update(N, x, L);
			it = adj[x].upper_bound(x);
			if(it == adj[x].end()) {
				y = *adj[x].begin();
				update(N, R, n), update(N, 1, y);
			}
			else {
				y = *it, update(N, R, y);
			}
		}
	}
	solve(0, N - 1, 1);
	for(int i = 0; i < N; i++) p[i] = {{one[i], two[i]}, col[i]};
	sort(p, p + N);
	for(int i = 0; i < N; i++) printf("%d ", p[i].y);
}


#include<bits/stdc++.h>

using namespace std;

using INT = long long;

#define NN 101000

int A[NN], B[NN], id[NN];
vector<int> rg[NN];
int nn = 0;
map<pair<int, int>, int> mp;
vector<int> adj[NN];
int ans[NN];

int smax(int &u, int v) {
	if(u < v) u = v;
}

int update(int u, int v, int id) {
	if(u > v) swap(u, v);
	if(mp.count({u, v})) {
		int x = mp[{u, v}];
		adj[id].push_back(x);
		adj[x].push_back(id);
	} else mp[{u, v}] = id;
}

int qf, qb, q[NN], sz[NN], fa[NN], vst[NN];

int find_root(int u){
	qf=qb=0;
	q[qb++]=u; fa[u]=0;
	while(qf<qb){
		u=q[qf++];
		for(int v : adj[u]) {
			if(v==fa[u] || vst[v]) continue;
			fa[v]=u;
			q[qb++]=v;
		}
	}
	nn=qb;
	for(int i=nn; i--; ){
		sz[u=q[i]]=1;
		int mx=0;
		for(int v : adj[u]) {
			if(v==fa[u] || vst[v]) continue;
			smax(mx, sz[v]);
			sz[u]+=sz[v];
		}
		if(mx*2<=nn && sz[u]*2>=nn) return u;
	}
}

void solve(int u, int mx = 1){
	u=find_root(u);

	vst[u]=1; ans[u] = mx;

	for(int v : adj[u]) {
		if(!vst[v]) solve(v, mx+1);
	}

	return ;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif
	int n, m;
	cin >> n >> m;
	for(int i=1; i<=m; i++) {
		scanf("%d %d", &A[i], &B[i]);
		if(A[i] > B[i]) swap(A[i], B[i]);
		id[i] = i;
	}

	sort(id+1, id+m+1, [&] (int u, int v) {
		if(B[u] != B[v]) return B[u] < B[v];
		return A[u] > A[v];
	});

	vector<int> buf;
	int pos = 0;
	for(int i=1; i<=m; i++) {
		while(pos < B[id[i]]) {
			pos++;
			buf.push_back(pos);
		} nn++;
		while(buf.back() != A[id[i]]) {
			rg[nn].push_back(buf.back());
			buf.pop_back();
		}
		rg[nn].push_back(A[id[i]]); buf.push_back(B[id[i]]);
	}

	while(pos < n) {
		pos++;
		buf.push_back(pos);
	} nn++;

	for(auto u : buf) {
		rg[nn].push_back(u);
	}

	for(int i=1; i<=nn; i++) {
		sort(rg[i].begin(), rg[i].end());
		reverse(rg[i].begin(), rg[i].end());
		id[i] = i;
	}

	sort(id+1, id+nn+1, [&] (int u, int v) {
		for(int i=0; i<rg[u].size(); i++) {
			if(rg[u][i] != rg[v][i]) {
				return rg[u][i] < rg[v][i];
			}
		}
	});

	for(int i=1; i<=nn; i++) {
		int u = id[i];
		for(int j=1; j<rg[u].size(); j++) {
			update(rg[u][j-1], rg[u][j], i);
		}
		update(rg[u].back(), rg[u][0], i);
	}

	int N = nn;
	solve(1);

	for(int i=1; i<=N; i++) {
		printf("%d ", ans[i]);
	} puts("");

	return 0;
}


#include<bits/stdc++.h>
#define y second
#define x first

using namespace std;
using INT = long long;
using pii = pair<int, int>;
using ppi = pair<pii, int>;

const int NN = 101010;

multiset<int> s;
multiset<int> :: iterator iit;

set<int> adj[NN];
set<int> :: iterator it;

int B[NN], n;
int st[NN], ed[NN];

void add(int u, int x) {
	for(; u <= n; u += u & -u) B[u] += x;
}
int calc(int u) {int ans = 0;
	for(; u; u ^= u & -u) ans += B[u];
	return ans;
}

int one[NN], two[NN], col[NN];
ppi p[NN];

void update(int u, int x) {
	if(x > two[u]) {
		two[u] = x;
		if(two[u] > one[u]) swap(one[u], two[u]);
	}
}
void update(int u, int L, int R) {
	if(L == R) update(u, L);
	else update(u, R - 1), update(u, R);
}

void solve(int L, int R, int c) {
	int md = L + R >> 1; col[md] = c;
	if(L < md) solve(L, md - 1, c + 1);
	if(md < R) solve(md + 1, R, c + 1);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
#endif

	int m; scanf("%d %d", &n, &m);
	for(int i = 1; i <= m; i++) {
		scanf("%d %d", st + i, ed + i);
		if(st[i] > ed[i]) swap(st[i], ed[i]);

		add(st[i], 1), s.insert(st[i]);
		add(ed[i], 1), s.insert(ed[i]);
		adj[st[i]].insert(ed[i]);
		adj[ed[i]].insert(st[i]);
	}
	int L, R, x, y, N = 1;
	for(int i = 1; i <= m; i++) {
		if(calc(ed[i] - 1) - calc(st[i]) == 0) {
			update(0, L = st[i], R = ed[i]);
			break;
		}
	}
	for(; ; N++, L = x, R = y) {
		add(L, -1), s.erase(s.find(L));
		add(R, -1), s.erase(s.find(R));
		adj[L].erase(R), adj[R].erase(L);
		if(s.empty()) {
			if(L > R) update(N, R, L);
			else update(N, 1, L), update(N, R, n);
			N++; break;
		}
		iit = s.upper_bound(L);
		if(iit == s.begin()) {
			x = *s.rbegin();
			update(N, 1, L), update(N, x, n);
			y = *adj[x].begin();
			update(N, R, y);
		}
		else {
			x = *--iit, update(N, x, L);
			it = adj[x].upper_bound(x);
			if(it == adj[x].end()) {
				y = *adj[x].begin();
				update(N, R, n), update(N, 1, y);
			}
			else {
				y = *it, update(N, R, y);
			}
		}
	}
	solve(0, N - 1, 1);
	for(int i = 0; i < N; i++) p[i] = {{one[i], two[i]}, col[i]};
	sort(p, p + N);
	for(int i = 0; i < N; i++) printf("%d ", p[i].y);
}


#include <bits/stdc++.h>
#define SZ(x) ((int) (x).size())
using namespace std;

typedef long long i64;

const int NMAX = 100005;
const int MOD = 1e9 + 7;
const int BASE = 31;

class Tree {
public:
    Tree(int n):
        adj(n) {}

    void addEdge(int from, int to) {
        adj[from].push_back(to);
        adj[to].push_back(from);
    }

    vector<int> getColoring() {
        subtree = vector<int>(SZ(adj));
        forbidden = vector<bool>(SZ(adj), false);
        vector<int> coloring(SZ(adj));
        solve(0, coloring);
        return coloring;
    }

private:
    vector<vector<int>> adj;
    vector<int> subtree;
    vector<bool> forbidden;

    int total;

    void solve(int root, vector<int>& coloring, int lvl = 1) {
        total = 0;
        dfs(root);
        root = choose(root);
        coloring[root] = lvl;
        forbidden[root] = true;
        for (int to: adj[root]) {
            if (!forbidden[to]) {
                solve(to, coloring, lvl + 1);
            }
        }
    }

    void dfs(int node, int prev = -1) {
        subtree[node] = 1;
        total++;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            dfs(to, node);
            subtree[node] += subtree[to];
        }
    }

    int choose(int node, int prev = -1) {
        bool good = true;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            good &= subtree[to] * 2 <= total;
        }
        good &= (total - subtree[node]) * 2 <= total;
        if (good) {
            return node;
        }
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            int x = choose(to, node);
            if (x != -1) {
                return x;
            }
        }
        return -1;
    }
};

vector<int> G[NMAX];

vector<int> buildHashes(const vector<int>& a) {
    vector<int> ret(SZ(a));
    int h = 0;
    for (int i = 0; i < SZ(a); ++i) {
        h = ((int64_t) h * BASE + a[i]) % MOD;
        ret[i] = h;
    }
    return ret;
}

int main() {
    #ifdef LOCAL_RUN
    freopen("task.in", "r", stdin);
    freopen("task.out", "w", stdout);
    //freopen("task.err", "w", stderr);
    #endif // ONLINE_JUDGE
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;

    map<pair<int, int>, int> indexes;
    vector<int> firstNode(m, -1), secondNode(m, -1);
    vector<pair<int, int>> dg;
    for (int i = 0; i < m; ++i) {
        int x, y;
        cin >> x >> y;
        x--; y--;
        G[x].push_back(y);
        G[y].push_back(x);
        if (x > y) {
            swap(x, y);
        }
        indexes[make_pair(x, y)] = i;
        dg.push_back(make_pair(x, y));
    }

    for (int i = 0; i < n; ++i) {
        G[i].push_back((i + 1) % n);
        sort(G[i].begin(), G[i].end());
    }

    vector<bool> used(n, false);
    int nodes = 0;
    vector<vector<int>> vadj;
    auto doStuff = [&](int prev, int node) -> void {
        int start = prev;
        vector<pair<int, int>> diags;
        vector<int> vertexes = {prev};
        if (node != (prev + 1) % n) {
            diags.push_back(make_pair(prev, node));
        }
        while (node != start) {
            vertexes.push_back(node);
            int pos = lower_bound(G[node].begin(), G[node].end(),
                    prev) - G[node].begin() - 1;
            if (pos == -1) pos += SZ(G[node]);
            int next = G[node][pos];
            if (next != (node + 1) % n) {
                diags.push_back(make_pair(node, next));
            } else {
                used[node] = true;
            }
            prev = node;
            node = next;
        }
        for (pair<int, int> p: diags) {
            if (p.first > p.second) {
                swap(p.first, p.second);
                int ind = indexes[p];
                secondNode[ind] = nodes;
            } else {
                int ind = indexes[p];
                firstNode[ind] = nodes;
            }
        }
        nodes++;
        sort(vertexes.begin(), vertexes.end());
        reverse(vertexes.begin(), vertexes.end());
        vadj.push_back(vertexes);
    };
    for (int i = 0; i < n; ++i) {
        if (!used[i]) {
            used[i] = true;
            int start = i;
            int node = (i + 1) % n;
            int prev = i;
            doStuff(prev, node);
        }
    }
    for (int i = 0; i < m; ++i) {
        if (firstNode[i] == -1) {
            doStuff(dg[i].first, dg[i].second);
        }
        if (secondNode[i] == -1) {
            doStuff(dg[i].second, dg[i].first);
        }
    }
    vector<int> nind(nodes);
    vector<vector<int>> hashes(nodes);
    for (int i = 0; i < nodes; ++i) {
        hashes[i] = buildHashes(vadj[i]);
    }
    for (int i = 0; i < nodes; ++i) {
        nind[i] = i;
    }
    sort(nind.begin(), nind.end(), [&](int a, int b) -> bool {
        int step;
        for (step = 1; step < SZ(vadj[a]) && step < SZ(vadj[b]); step *= 2);
        int pos = -1;
        for ( ; step > 0; step /= 2) {
            if (pos + step < SZ(vadj[a]) && pos + step < SZ(vadj[b]) &&
                    hashes[a][pos + step] == hashes[b][pos + step]) {
                pos += step;
            }
        }
        ++pos;
        if (pos == SZ(vadj[a])) {
            return true;
        } else if (pos == SZ(vadj[b])) {
            return false;
        } else {
            return vadj[a][pos] < vadj[b][pos];
        }
    });
    vector<int> xpos(nodes);
    for (int i = 0; i < nodes; ++i) {
        xpos[nind[i]] = nodes - i - 1;
    }
    Tree t(nodes);
    for (int i = 0; i < m; ++i) {
        assert(firstNode[i] != -1);
        assert(secondNode[i] != -1);
        t.addEdge(xpos[firstNode[i]], xpos[secondNode[i]]);
    }
    vector<int> colors = t.getColoring();
    for (int v: colors) {
        cout << v << ' ';
    }
    cout << endl;
}


#include <bits/stdc++.h>
#define SZ(x) ((int) (x).size())
using namespace std;

typedef long long i64;

const int NMAX = 100005;
const int MOD = 1e9 + 7;
const int BASE = 31;

class Tree {
public:
    Tree(int n):
        adj(n) {}

    void addEdge(int from, int to) {
        adj[from].push_back(to);
        adj[to].push_back(from);
    }

    vector<int> getColoring() {
        subtree = vector<int>(SZ(adj));
        forbidden = vector<bool>(SZ(adj), false);
        vector<int> coloring(SZ(adj));
        solve(0, coloring);
        return coloring;
    }

private:
    vector<vector<int>> adj;
    vector<int> subtree;
    vector<bool> forbidden;

    int total;

    void solve(int root, vector<int>& coloring, int lvl = 1) {
        total = 0;
        dfs(root);
        root = choose(root);
        coloring[root] = lvl;
        forbidden[root] = true;
        for (int to: adj[root]) {
            if (!forbidden[to]) {
                solve(to, coloring, lvl + 1);
            }
        }
    }

    void dfs(int node, int prev = -1) {
        subtree[node] = 1;
        total++;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            dfs(to, node);
            subtree[node] += subtree[to];
        }
    }

    int choose(int node, int prev = -1) {
        bool good = true;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            good &= subtree[to] * 2 <= total;
        }
        good &= (total - subtree[node]) * 2 <= total;
        if (good) {
            return node;
        }
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            int x = choose(to, node);
            if (x != -1) {
                return x;
            }
        }
        return -1;
    }
};

vector<int> G[NMAX];

vector<uint64_t> buildHashes(const vector<int>& a) {
    vector<uint64_t> ret(SZ(a));
    uint64_t h = 0;
    for (int i = 0; i < SZ(a); ++i) {
        h = h * BASE + a[i];
        ret[i] = h;
    }
    return ret;
}

int main() {
    #ifdef LOCAL_RUN
    freopen("task.in", "r", stdin);
    freopen("task.out", "w", stdout);
    //freopen("task.err", "w", stderr);
    #endif // ONLINE_JUDGE
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;

    map<pair<int, int>, int> indexes;
    vector<int> firstNode(m, -1), secondNode(m, -1);
    vector<pair<int, int>> dg;
    for (int i = 0; i < m; ++i) {
        int x, y;
        cin >> x >> y;
        x--; y--;
        G[x].push_back(y);
        G[y].push_back(x);
        if (x > y) {
            swap(x, y);
        }
        indexes[make_pair(x, y)] = i;
        dg.push_back(make_pair(x, y));
    }

    for (int i = 0; i < n; ++i) {
        G[i].push_back((i + 1) % n);
        sort(G[i].begin(), G[i].end());
    }

    vector<bool> used(n, false);
    int nodes = 0;
    vector<vector<int>> vadj;
    auto doStuff = [&](int prev, int node) -> void {
        int start = prev;
        vector<pair<int, int>> diags;
        vector<int> vertexes = {prev};
        if (node != (prev + 1) % n) {
            diags.push_back(make_pair(prev, node));
        }
        while (node != start) {
            vertexes.push_back(node);
            int pos = lower_bound(G[node].begin(), G[node].end(),
                    prev) - G[node].begin() - 1;
            if (pos == -1) pos += SZ(G[node]);
            int next = G[node][pos];
            if (next != (node + 1) % n) {
                diags.push_back(make_pair(node, next));
            } else {
                used[node] = true;
            }
            prev = node;
            node = next;
        }
        for (pair<int, int> p: diags) {
            if (p.first > p.second) {
                swap(p.first, p.second);
                int ind = indexes[p];
                secondNode[ind] = nodes;
            } else {
                int ind = indexes[p];
                firstNode[ind] = nodes;
            }
        }
        nodes++;
        sort(vertexes.begin(), vertexes.end());
        reverse(vertexes.begin(), vertexes.end());
        vadj.push_back(vertexes);
    };
    for (int i = 0; i < n; ++i) {
        if (!used[i]) {
            used[i] = true;
            int start = i;
            int node = (i + 1) % n;
            int prev = i;
            doStuff(prev, node);
        }
    }
    for (int i = 0; i < m; ++i) {
        if (firstNode[i] == -1) {
            doStuff(dg[i].first, dg[i].second);
        }
        if (secondNode[i] == -1) {
            doStuff(dg[i].second, dg[i].first);
        }
    }
    vector<int> nind(nodes);
    vector<vector<uint64_t>> hashes(nodes);
    for (int i = 0; i < nodes; ++i) {
        hashes[i] = buildHashes(vadj[i]);
    }
    for (int i = 0; i < nodes; ++i) {
        nind[i] = i;
    }
    sort(nind.begin(), nind.end(), [&](int a, int b) -> bool {
        int step;
        for (step = 1; step < SZ(vadj[a]) && step < SZ(vadj[b]); step *= 2);
        int pos = -1;
        for ( ; step > 0; step /= 2) {
            if (pos + step < SZ(vadj[a]) && pos + step < SZ(vadj[b]) &&
                    hashes[a][pos + step] == hashes[b][pos + step]) {
                pos += step;
            }
        }
        ++pos;
        if (pos == SZ(vadj[a])) {
            return false;
        } else if (pos == SZ(vadj[b])) {
            return true;
        } else {
            return vadj[a][pos] > vadj[b][pos];
        }
    });
    vector<int> xpos(nodes);
    for (int i = 0; i < nodes; ++i) {
        xpos[nind[i]] = nodes - i - 1;
    }
    Tree t(nodes);
    for (int i = 0; i < m; ++i) {
        assert(firstNode[i] != -1);
        assert(secondNode[i] != -1);
        t.addEdge(xpos[firstNode[i]], xpos[secondNode[i]]);
    }
    vector<int> colors = t.getColoring();
    for (int v: colors) {
        cout << v << ' ';
    }
    cout << endl;
}


#include <bits/stdc++.h>
#define SZ(x) ((int) (x).size())
using namespace std;

typedef long long i64;

const int NMAX = 100005;
const int MOD = 1e9 + 7;
const int BASE = 31;

class Tree {
public:
    Tree(int n):
        adj(n) {}

    void addEdge(int from, int to) {
        adj[from].push_back(to);
        adj[to].push_back(from);
    }

    vector<int> getColoring() {
        subtree = vector<int>(SZ(adj));
        forbidden = vector<bool>(SZ(adj), false);
        vector<int> coloring(SZ(adj));
        solve(0, coloring);
        return coloring;
    }

private:
    vector<vector<int>> adj;
    vector<int> subtree;
    vector<bool> forbidden;

    int total;

    void solve(int root, vector<int>& coloring, int lvl = 1) {
        total = 0;
        dfs(root);
        root = choose(root);
        coloring[root] = lvl;
        forbidden[root] = true;
        for (int to: adj[root]) {
            if (!forbidden[to]) {
                solve(to, coloring, lvl + 1);
            }
        }
    }

    void dfs(int node, int prev = -1) {
        subtree[node] = 1;
        total++;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            dfs(to, node);
            subtree[node] += subtree[to];
        }
    }

    int choose(int node, int prev = -1) {
        bool good = true;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            good &= subtree[to] * 2 <= total;
        }
        good &= (total - subtree[node]) * 2 <= total;
        if (good) {
            return node;
        }
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            int x = choose(to, node);
            if (x != -1) {
                return x;
            }
        }
        return -1;
    }
};

vector<int> G[NMAX];

vector<int> buildHashes(const vector<int>& a) {
    vector<int> ret(SZ(a));
    int h = 0;
    for (int i = 0; i < SZ(a); ++i) {
        h = ((int64_t) h * BASE + a[i]) % MOD;
        ret[i] = h;
    }
    return ret;
}

int main() {
    #ifdef LOCAL_RUN
    freopen("task.in", "r", stdin);
    freopen("task.out", "w", stdout);
    //freopen("task.err", "w", stderr);
    #endif // ONLINE_JUDGE
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;

    map<pair<int, int>, int> indexes;
    vector<int> firstNode(m, -1), secondNode(m, -1);
    vector<pair<int, int>> dg;
    for (int i = 0; i < m; ++i) {
        int x, y;
        cin >> x >> y;
        x--; y--;
        G[x].push_back(y);
        G[y].push_back(x);
        if (x > y) {
            swap(x, y);
        }
        indexes[make_pair(x, y)] = i;
        dg.push_back(make_pair(x, y));
    }

    for (int i = 0; i < n; ++i) {
        G[i].push_back((i + 1) % n);
        sort(G[i].begin(), G[i].end());
    }

    vector<bool> used(n, false);
    int nodes = 0;
    vector<vector<int>> vadj;
    auto doStuff = [&](int prev, int node) -> void {
        int start = prev;
        vector<pair<int, int>> diags;
        vector<int> vertexes = {prev};
        if (node != (prev + 1) % n) {
            diags.push_back(make_pair(prev, node));
        }
        while (node != start) {
            vertexes.push_back(node);
            int pos = lower_bound(G[node].begin(), G[node].end(),
                    prev) - G[node].begin() - 1;
            if (pos == -1) pos += SZ(G[node]);
            int next = G[node][pos];
            if (next != (node + 1) % n) {
                diags.push_back(make_pair(node, next));
            } else {
                used[node] = true;
            }
            prev = node;
            node = next;
        }
        for (pair<int, int> p: diags) {
            if (p.first > p.second) {
                swap(p.first, p.second);
                int ind = indexes[p];
                secondNode[ind] = nodes;
            } else {
                int ind = indexes[p];
                firstNode[ind] = nodes;
            }
        }
        nodes++;
        sort(vertexes.begin(), vertexes.end());
        reverse(vertexes.begin(), vertexes.end());
        vadj.push_back(vertexes);
    };
    for (int i = 0; i < n; ++i) {
        if (!used[i]) {
            used[i] = true;
            int start = i;
            int node = (i + 1) % n;
            int prev = i;
            doStuff(prev, node);
        }
    }
    for (int i = 0; i < m; ++i) {
        if (firstNode[i] == -1) {
            doStuff(dg[i].first, dg[i].second);
        }
        if (secondNode[i] == -1) {
            doStuff(dg[i].second, dg[i].first);
        }
    }
    vector<int> nind(nodes);
    vector<vector<int>> hashes(nodes);
    for (int i = 0; i < nodes; ++i) {
        hashes[i] = buildHashes(vadj[i]);
    }
    for (int i = 0; i < nodes; ++i) {
        nind[i] = i;
    }
    sort(nind.begin(), nind.end(), [&](int a, int b) -> bool {
        int step;
        for (step = 1; step < SZ(vadj[a]) && step < SZ(vadj[b]); step *= 2);
        int pos = -1;
        for ( ; step > 0; step /= 2) {
            if (pos + step < SZ(vadj[a]) && pos + step < SZ(vadj[b]) &&
                    hashes[a][pos + step] == hashes[b][pos + step]) {
                pos += step;
            }
        }
        ++pos;
        if (pos == SZ(vadj[a])) {
            return true;
        } else if (pos == SZ(vadj[b])) {
            return false;
        } else {
            return vadj[a][pos] < vadj[b][pos];
        }
    });
    vector<int> xpos(nodes);
    for (int i = 0; i < nodes; ++i) {
        xpos[nind[i]] = i;
    }
    Tree t(nodes);
    for (int i = 0; i < m; ++i) {
        assert(firstNode[i] != -1);
        assert(secondNode[i] != -1);
        t.addEdge(xpos[firstNode[i]], xpos[secondNode[i]]);
    }
    vector<int> colors = t.getColoring();
    for (int v: colors) {
        cout << v << ' ';
    }
    cout << endl;
}


#include <bits/stdc++.h>
#define SZ(x) ((int) (x).size())
using namespace std;

typedef long long i64;

const int NMAX = 100005;
const int MOD = 1e9 + 9;
const int BASE = 31;

class Tree {
public:
    Tree(int n):
        adj(n) {}

    void addEdge(int from, int to) {
        adj[from].push_back(to);
        adj[to].push_back(from);
    }

    vector<int> getColoring() {
        subtree = vector<int>(SZ(adj));
        forbidden = vector<bool>(SZ(adj), false);
        vector<int> coloring(SZ(adj));
        solve(0, coloring);
        return coloring;
    }

private:
    vector<vector<int>> adj;
    vector<int> subtree;
    vector<bool> forbidden;

    int total;

    void solve(int root, vector<int>& coloring, int lvl = 1) {
        total = 0;
        dfs(root);
        root = choose(root);
        coloring[root] = lvl;
        forbidden[root] = true;
        for (int to: adj[root]) {
            if (!forbidden[to]) {
                solve(to, coloring, lvl + 1);
            }
        }
    }

    void dfs(int node, int prev = -1) {
        subtree[node] = 1;
        total++;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            dfs(to, node);
            subtree[node] += subtree[to];
        }
    }

    int choose(int node, int prev = -1) {
        bool good = true;
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            good &= subtree[to] * 2 <= total;
        }
        good &= (total - subtree[node]) * 2 <= total;
        if (good) {
            return node;
        }
        for (int to: adj[node]) {
            if (to == prev || forbidden[to]) {
                continue;
            }
            int x = choose(to, node);
            if (x != -1) {
                return x;
            }
        }
        return -1;
    }
};

vector<int> G[NMAX];

vector<int> buildHashes(const vector<int>& a) {
    vector<int> ret(SZ(a));
    int h = 0;
    for (int i = 0; i < SZ(a); ++i) {
        h = ((int64_t) h * BASE + a[i]) % MOD;
        ret[i] = h;
    }
    return ret;
}

int main() {
    #ifdef LOCAL_RUN
    freopen("task.in", "r", stdin);
    freopen("task.out", "w", stdout);
    //freopen("task.err", "w", stderr);
    #endif // ONLINE_JUDGE
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;

    map<pair<int, int>, int> indexes;
    vector<int> firstNode(m, -1), secondNode(m, -1);
    vector<pair<int, int>> dg;
    for (int i = 0; i < m; ++i) {
        int x, y;
        cin >> x >> y;
        x--; y--;
        G[x].push_back(y);
        G[y].push_back(x);
        if (x > y) {
            swap(x, y);
        }
        indexes[make_pair(x, y)] = i;
        dg.push_back(make_pair(x, y));
    }

    for (int i = 0; i < n; ++i) {
        G[i].push_back((i + 1) % n);
        sort(G[i].begin(), G[i].end());
    }

    vector<bool> used(n, false);
    int nodes = 0;
    vector<vector<int>> vadj;
    auto doStuff = [&](int prev, int node) -> void {
        int start = prev;
        vector<pair<int, int>> diags;
        vector<int> vertexes = {prev};
        if (node != (prev + 1) % n) {
            diags.push_back(make_pair(prev, node));
        }
        while (node != start) {
            vertexes.push_back(node);
            int pos = lower_bound(G[node].begin(), G[node].end(),
                    prev) - G[node].begin() - 1;
            if (pos == -1) pos += SZ(G[node]);
            int next = G[node][pos];
            if (next != (node + 1) % n) {
                diags.push_back(make_pair(node, next));
            } else {
                used[node] = true;
            }
            prev = node;
            node = next;
        }
        for (pair<int, int> p: diags) {
            if (p.first > p.second) {
                swap(p.first, p.second);
                int ind = indexes[p];
                secondNode[ind] = nodes;
            } else {
                int ind = indexes[p];
                firstNode[ind] = nodes;
            }
        }
        nodes++;
        sort(vertexes.begin(), vertexes.end());
        reverse(vertexes.begin(), vertexes.end());
        vadj.push_back(vertexes);
    };
    for (int i = 0; i < n; ++i) {
        if (!used[i]) {
            used[i] = true;
            int start = i;
            int node = (i + 1) % n;
            int prev = i;
            doStuff(prev, node);
        }
    }
    for (int i = 0; i < m; ++i) {
        if (firstNode[i] == -1) {
            doStuff(dg[i].first, dg[i].second);
        }
        if (secondNode[i] == -1) {
            doStuff(dg[i].second, dg[i].first);
        }
    }
    vector<int> nind(nodes);
    vector<vector<int>> hashes(nodes);
    for (int i = 0; i < nodes; ++i) {
        hashes[i] = buildHashes(vadj[i]);
    }
    for (int i = 0; i < nodes; ++i) {
        nind[i] = i;
    }
    sort(nind.begin(), nind.end(), [&](int a, int b) -> bool {
        int step;
        for (step = 1; step < SZ(vadj[a]) && step < SZ(vadj[b]); step *= 2);
        int pos = -1;
        for ( ; step > 0; step /= 2) {
            if (pos + step < SZ(vadj[a]) && pos + step < SZ(vadj[b]) &&
                    hashes[a][pos + step] == hashes[b][pos + step]) {
                pos += step;
            }
        }
        ++pos;
        if (pos == SZ(vadj[a])) {
            return false;
        } else if (pos == SZ(vadj[b])) {
            return true;
        } else {
            return vadj[a][pos] > vadj[b][pos];
        }
    });
    vector<int> xpos(nodes);
    for (int i = 0; i < nodes; ++i) {
        xpos[nind[i]] = nodes - i - 1;
    }
    Tree t(nodes);
    for (int i = 0; i < m; ++i) {
        assert(firstNode[i] != -1);
        assert(secondNode[i] != -1);
        t.addEdge(xpos[firstNode[i]], xpos[secondNode[i]]);
    }
    vector<int> colors = t.getColoring();
    for (int v: colors) {
        cout << v << ' ';
    }
    cout << endl;
}