#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 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<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;
}


#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);
    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;
    }

    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;
    for (int i = 0; i < n; ++i) {
        if (!used[i]) {
            used[i] = true;
            int start = i;
            int node = (i + 1) % n;
            int prev = i;
            vector<pair<int, int>> diags;
            vector<int> vertexes = {prev};
            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];
                if (firstNode[ind] == -1) {
                    firstNode[ind] = nodes;
                } else {
                    secondNode[ind] = nodes;
                }
            }
            nodes++;
            sort(vertexes.begin(), vertexes.end());
            reverse(vertexes.begin(), vertexes.end());
            vadj.push_back(vertexes);
        }
    }
    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<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 {
        return vadj[a] > vadj[b];
    });
    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));
    uint32_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<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;
}


#include <bits/stdc++.h>
#define F first
#define S second
#define X real()
#define Y imag()
using namespace std;
typedef long long ll;
typedef long double ld;

int n;

int dt(pair<int, int> x){
	if (x.F<x.S) return x.S-x.F;
	return x.S+n-x.F;
}

vector<int> g[101010];

vector<int> tv[101010];

set<int> h[101010];

int pf[101010];

int col[101010];
int del[101010];
int aps[101010];

void dfs0(int x, int p){
	aps[x]=1;
	for (int nx:g[x]){
		if (nx==p) continue;
		if (del[nx]) continue;
		dfs0(nx, x);
		aps[x]+=aps[nx];
	}
}

int ct;

void dfs1(int x, int p, int sz){
	int ma=0;
	for (int nx:g[x]){
		if (nx==p) continue;
		if (del[nx]) continue;
		ma=max(ma, aps[nx]);
	}
	if (max(ma, sz-aps[x])<=sz/2){
		ct=x;
	}
	for (int nx:g[x]){
		if (nx==p) continue;
		if (del[nx]) continue;
		dfs1(nx, x, sz);
	}
}

void solve(int x, int cc){
	dfs0(x, -1);
	ct=-1;
	dfs1(x, -1, aps[x]);
	assert(ct!=-1);
	assert(cc<=20);
	col[ct]=cc;
	del[ct]=1;
	for (int nx:g[ct]){
		if (!del[nx]){
			solve(nx, cc+1);
		}
	}
}

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	int m;
	cin>>n>>m;
	if (m==0){
		cout<<1<<endl;
		return 0;
	}
	vector<pair<int, int> > iv;
	for (int i=0;i<m;i++){
		int a,b;
		cin>>a>>b;
		a--;
		b--;
		if (a>b) swap(a, b);
		int d1=b-a;
		int d2=a+n-b;
		if (d1<d2){
			iv.push_back({a, b});
		}
		else{
			iv.push_back({b, a});
		}
	}
	auto cmp = [](pair<int, int> a, pair<int, int> b) {
		return dt(a)<dt(b);
	};
	sort(iv.begin(), iv.end(), cmp);
	set<int> ver;
	for (int i=0;i<n;i++){
		ver.insert(i);
	}
	for (int i=0;i<m;i++){
		tv[i].push_back(iv[i].F);
		tv[i].push_back(iv[i].S);
		set<int> adj;
		if (iv[i].F<iv[i].S){
			auto it=ver.lower_bound(iv[i].F+1);
			while (it!=ver.end()&&(*it)>iv[i].F&&(*it)<iv[i].S){
				for (int a:h[*it]){
					adj.insert(a);
				}
				tv[i].push_back(*it);
				auto lol=it;
				it++;
				ver.erase(lol);
			}
		}
		else{
			auto it=ver.lower_bound(iv[i].S+1);
			while (it!=ver.end()&&(*it)>iv[i].S){
				for (int a:h[*it]){
					adj.insert(a);
				}
				tv[i].push_back(*it);
				auto lol=it;
				it++;
				ver.erase(lol);
			}
			it=ver.begin();
			while (it!=ver.end()&&(*it)<iv[i].F){
				for (int a:h[*it]){
					adj.insert(a);
				}
				tv[i].push_back(*it);
				auto lol=it;
				it++;
				ver.erase(lol);
			}
		}
		for (int a:adj){
			if (pf[a]) continue;
			pf[a]=1;
			g[a].push_back(i);
			g[i].push_back(a);
		}
		h[iv[i].F].insert(i);
		h[iv[i].S].insert(i);
	}
	for (int x:ver){
		tv[m].push_back(x);
	}
	for (int i=0;i<m;i++){
		if (pf[i]==0){
			g[m].push_back(i);
			g[i].push_back(m);
			pf[i]=1;
		}
	}
	for (int i=0;i<=m;i++){
		sort(tv[i].rbegin(), tv[i].rend());
	}
	solve(m, 1);
	vector<pair<vector<int>, int> > asdf;
	for (int i=0;i<=m;i++){
		asdf.push_back({tv[i], col[i]});
	}
	sort(asdf.begin(), asdf.end());
	for (int i=0;i<=m;i++){
		cout<<asdf[i].S<<" ";
	}
	cout<<endl;
}


#include <bits/stdc++.h>
#define F first
#define S second
#define X real()
#define Y imag()
using namespace std;
typedef long long ll;
typedef long double ld;

int n;

int dt(pair<int, int> x){
	if (x.F<x.S) return x.S-x.F;
	return x.S+n-x.F;
}

vector<int> g[101010];

vector<int> tv[101010];

set<int> h[101010];

int pf[101010];

int col[101010];
int del[101010];
int aps[101010];

void dfs0(int x, int p){
	aps[x]=1;
	for (int nx:g[x]){
		if (nx==p) continue;
		if (del[nx]) continue;
		dfs0(nx, x);
		aps[x]+=aps[nx];
	}
}

int ct;

void dfs1(int x, int p, int sz){
	int ma=0;
	for (int nx:g[x]){
		if (nx==p) continue;
		if (del[nx]) continue;
		ma=max(ma, aps[nx]);
	}
	if (max(ma, sz-aps[x])<=sz/2){
		ct=x;
	}
	for (int nx:g[x]){
		if (nx==p) continue;
		if (del[nx]) continue;
		dfs1(nx, x, sz);
	}
}

void solve(int x, int cc){
	dfs0(x, -1);
	ct=-1;
	dfs1(x, -1, aps[x]);
	assert(ct!=-1);
	assert(cc<=20);
	col[ct]=cc;
	del[ct]=1;
	for (int nx:g[ct]){
		if (!del[nx]){
			solve(nx, cc+1);
		}
	}
}

int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	int m;
	cin>>n>>m;
	if (m==0){
		cout<<1<<endl;
		return 0;
	}
	vector<pair<int, int> > iv;
	for (int i=0;i<m;i++){
		int a,b;
		cin>>a>>b;
		a--;
		b--;
		if (a>b) swap(a, b);
		int d1=b-a;
		int d2=a+n-b;
		if (d1<d2){
			iv.push_back({a, b});
		}
		else{
			iv.push_back({b, a});
		}
	}
	auto cmp = [](pair<int, int> a, pair<int, int> b) {
		return dt(a)<dt(b);
	};
	sort(iv.begin(), iv.end(), cmp);
	set<int> ver;
	for (int i=0;i<n;i++){
		ver.insert(i);
	}
	for (int i=0;i<m;i++){
		tv[i].push_back(iv[i].F);
		tv[i].push_back(iv[i].S);
		set<int> adj;
		if (iv[i].F<iv[i].S){
			auto it=ver.lower_bound(iv[i].F+1);
			while (it!=ver.end()&&(*it)>iv[i].F&&(*it)<iv[i].S){
				for (int a:h[*it]){
					adj.insert(a);
				}
				tv[i].push_back(*it);
				auto lol=it;
				it++;
// 				cout<<"er "<<(*lol)<<endl;
				ver.erase(lol);
			}
		}
		else{
			auto it=ver.lower_bound(iv[i].F+1);
			while (it!=ver.end()){
				for (int a:h[*it]){
					adj.insert(a);
				}
				tv[i].push_back(*it);
				auto lol=it;
				it++;
// 				cout<<"er "<<(*lol)<<endl;
				ver.erase(lol);
			}
			it=ver.begin();
			while (it!=ver.end()&&(*it)<iv[i].S){
				for (int a:h[*it]){
					adj.insert(a);
				}
				tv[i].push_back(*it);
				auto lol=it;
				it++;
// 				cout<<"er "<<(*lol)<<endl;
				ver.erase(lol);
			}
		}
// 		cout<<iv[i].F<<" t "<<iv[i].S<<endl;
		for (int a:adj){
			if (pf[a]) continue;
// 			cout<<"a "<<a<<endl;
			pf[a]=1;
			g[a].push_back(i);
			g[i].push_back(a);
		}
		h[iv[i].F].insert(i);
		h[iv[i].S].insert(i);
	}
	for (int x:ver){
		tv[m].push_back(x);
	}
	for (int i=0;i<m;i++){
		if (pf[i]==0){
			g[m].push_back(i);
			g[i].push_back(m);
			pf[i]=1;
		}
	}
	for (int i=0;i<=m;i++){
		sort(tv[i].rbegin(), tv[i].rend());
	}
	solve(m, 1);
	vector<pair<vector<int>, int> > asdf;
	for (int i=0;i<=m;i++){
		asdf.push_back({tv[i], col[i]});
	}
	sort(asdf.begin(), asdf.end());
	for (int i=0;i<=m;i++){
		/*
		for (int a:asdf[i].F){
			cout<<a<<" ";
		}
		cout<<endl;*/
		cout<<asdf[i].S<<" ";
// 		cout<<endl;
	}
	cout<<endl;
}


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

#define F first
#define S second

const int MAXN = 3e5 + 10;

int n, m, comp[MAXN];
vector<pair<int, int>> adj[MAXN];
vector<int> G[MAXN];
bool vis[MAXN];
pair<pair<int, int>, int> mx[MAXN], ord[MAXN];
int sec[MAXN], gec[MAXN], sz, tt, ff;

void go(int u, pair<int, int> e, int de = 0){
	if (vis[e.S]) return;
	vis[e.S] = 1;
	gec[tt++] = e.F;
	sec[sz++] = e.S;
	int v = e.F, pos;
	if (de){
		pos = lower_bound(adj[v].begin(), adj[v].end(), make_pair(u, -1)) - adj[v].begin();
		if (pos == adj[v].size() || adj[v][pos].F != u){
			pos = adj[v].size() - 1;
			if (adj[v][pos].F > v)
				go(u, adj[v][pos], 1);
			else
				go(u, adj[v][0], 1);
		}
		else{
			sec[sz++] = adj[v][pos].S;
			vis[sec[sz - 1]] = 1;
			return;
		}
	}
	else{
		pos = adj[v].size() - 1;
		if (adj[v][pos].F > v)
			go(u, adj[v][pos], 1);
		else
			go(u, adj[v][0], 1);
	}
}

bitset<MAXN> mark;
int sub[MAXN], ans[MAXN];

void init(int u, int p = -1){
	sub[u] = 1;
	for (int v : G[u])
		if (!mark[v] && p != v)
			init(v, u), sub[u] += sub[v];
}

void solve(int u, int c){
	init(u);

	int r = u; bool found = true;
	while(found){
		found = false;
		for (int v : G[r])
			if (sub[v] > sub[u] / 2 && sub[v] < sub[r]){
				r = v;
				found = true;
				break;
			}
	}

	mark[r] = true; ans[r] = c;
	for (int v : G[r]) if (!mark[v])
		solve(v, c + 1);
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < n; i++){
		int a = i, b = i+1;
		if (b == n) b = 0;
		adj[a].push_back({b, i<<1});
	}
	for (int i = n; i < n+m; i++){
		int a, b;	cin >> a >> b, a--, b--;
		adj[a].push_back({b, i<<1}), adj[b].push_back({a, i<<1^1});
	}
	for (int i = 0; i < n; i++) sort(adj[i].begin(), adj[i].end());
	for (int i = 0; i < n; i++)
		for (auto e:adj[i])
			if (!vis[e.S]){
				sz = tt = 0;
				gec[tt++] = i;
				go(i, e);
				sort(gec, gec + tt);
				tt = unique(gec, gec + tt) - gec;
				reverse(gec, gec + tt);
				for (int j = 0; j < sz; j++)
					mx[sec[j]] = {{gec[0], gec[1]}, gec[2]};
				ord[ff++] = mx[sec[0]];
			}
	sort(ord, ord + ff);
	ff = unique(ord, ord+ff) - ord;
	for (int i = 0; i < MAXN; i++)
		comp[i] = ff-1 - (lower_bound(ord, ord + ff, mx[i]) - ord);
	for (int i = n; i < n+m; i++)
		G[comp[i<<1]].push_back(comp[i<<1^1])
			, G[comp[i<<1^1]].push_back(comp[i<<1]);

	solve(0, 1);

	for (int i = 0; i < ff; i++)
		cout << ans[i] << " ";
	cout << "\n";
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

#define F first
#define S second

const int MAXN = 5e5 + 10;

int n, m, comp[MAXN];
vector<pair<int, int>> adj[MAXN];
vector<int> G[MAXN];
bool vis[MAXN];
pair<pair<int, int>, int> mx[MAXN], ord[MAXN];
int sec[MAXN], gec[MAXN], sz, tt, ff;

void go(int u, pair<int, int> e, int de = 0){
	if (vis[e.S]) return;
	vis[e.S] = 1;
	gec[tt++] = e.F;
	sec[sz++] = e.S;
	int v = e.F, pos;
	if (de){
		pos = lower_bound(adj[v].begin(), adj[v].end(), make_pair(u, -1)) - adj[v].begin();
		if (pos == adj[v].size() || adj[v][pos].F != u){
			pos = adj[v].size() - 1;
			go(u, adj[v][pos], 1);
		}
		else{
			sec[sz++] = adj[v][pos].S;
			vis[sec[sz - 1]] = 1;
			return;
		}
	}
	else{
		pos = adj[v].size() - 1;
		go(u, adj[v][pos], 1);
	}
}

bitset<MAXN> mark;
int sub[MAXN], ans[MAXN];

void init(int u, int p = -1){
	sub[u] = 1;
	for (int v : G[u])
		if (!mark[v] && p != v)
			init(v, u), sub[u] += sub[v];
}

void solve(int u, int c){
	init(u);

	int r = u; bool found = true;
	while(found){
		found = false;
		for (int v : G[r])
			if (sub[v] > sub[u] / 2 && sub[v] < sub[r]){
				r = v;
				found = true;
				break;
			}
	}

	mark[r] = true; ans[r] = c;
	for (int v : G[r]) if (!mark[v])
		solve(v, c + 1);
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < n; i++){
		int a = i, b = i+1;
		if (b == n) b = 0;
		adj[a].push_back({b, i<<1});
	}
	for (int i = n; i < n+m; i++){
		int a, b;	cin >> a >> b, a--, b--;
		adj[a].push_back({b, i<<1}), adj[b].push_back({a, i<<1^1});
	}
	for (int i = 0; i < n; i++) sort(adj[i].begin(), adj[i].end());
	for (int i = 0; i < n; i++)
		for (auto e:adj[i])
			if (!vis[e.S]){
				sz = tt = 0;
				gec[tt++] = i;
				go(i, e);
				sort(gec, gec + tt);
				tt = unique(gec, gec + tt) - gec;
				reverse(gec, gec + tt);
				for (int j = 0; j < sz; j++)
					mx[sec[j]] = {{gec[0], gec[1]}, gec[2]};
				ord[ff++] = mx[sec[0]];
			}
	sort(ord, ord + ff);
	ff = unique(ord, ord+ff) - ord;
	for (int i = 0; i < MAXN; i++)
		comp[i] = ff-1 - (lower_bound(ord, ord + ff, mx[i]) - ord);
	for (int i = n; i < n+m; i++)
		G[comp[i<<1]].push_back(comp[i<<1^1])
			, G[comp[i<<1^1]].push_back(comp[i<<1]);

	solve(0, 1);

	for (int i = 0; i < ff; i++)
		cout << ans[i] << " ";
	cout << "\n";
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

#define F first
#define S second

const int MAXN = 5e5 + 10;

int n, m, comp[MAXN];
vector<pair<int, int>> adj[MAXN];
vector<int> G[MAXN];
bool vis[MAXN];
pair<pair<int, int>, int> mx[MAXN], ord[MAXN];
int sec[MAXN], gec[MAXN], sz, tt, ff;

void go(int u, pair<int, int> e, int de = 0){
	if (vis[e.S]) return;
	vis[e.S] = 1;
	gec[tt++] = e.F;
	sec[sz++] = e.S;
	int v = e.F, pos;
	if (de){
		pos = lower_bound(adj[v].begin(), adj[v].end(), make_pair(u, -1)) - adj[v].begin();
		if (pos == adj[v].size() || adj[v][pos].F != u){
			pos = adj[v].size() - 1;
			go(u, adj[v][pos], 1);
		}
		else{
			sec[sz++] = adj[v][pos].S;
			vis[sec[sz - 1]] = 1;
			return;
		}
	}
	else{
		pos = adj[v].size() - 1;
		go(u, adj[v][pos], 1);
	}
}

bitset<MAXN> mark;
int sub[MAXN], ans[MAXN];

void init(int u, int p = -1){
	sub[u] = 1;
	for (int v : G[u])
		if (!mark[v] && p != v)
			init(v, u), sub[u] += sub[v];
}

void solve(int u, int c){
	init(u);

	int r = u; bool found = true;
	while(found){
		found = false;
		for (int v : G[r])
			if (sub[v] > sub[u] / 2 && sub[v] < sub[r]){
				r = v;
				found = true;
				break;
			}
	}

	mark[r] = true; ans[r] = c;
	for (int v : G[r]) if (!mark[v])
		solve(v, c + 1);
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < n; i++){
		int a = i, b = i+1;
		if (b == n) b = 0;
		adj[a].push_back({b, i<<1});
	}
	for (int i = n; i < n+m; i++){
		int a, b;	cin >> a >> b, a--, b--;
		adj[a].push_back({b, i<<1}), adj[b].push_back({a, i<<1^1});
	}
	for (int i = 0; i < n; i++) sort(adj[i].begin(), adj[i].end());
	for (int i = 0; i < n; i++)
		for (auto e:adj[i])
			if (!vis[e.S]){
				sz = tt = 0;
				gec[tt++] = i;
				go(i, e);
				sort(gec, gec + tt);
				tt = unique(gec, gec + tt) - gec;
				reverse(gec, gec + tt);
				for (int j = 0; j < sz; j++)
					mx[sec[j]] = {{gec[0], gec[1]}, gec[2]};
				ord[ff++] = mx[sec[0]];
			}
	sort(ord, ord + ff);
	ff = unique(ord, ord+ff) - ord;
	for (int i = 0; i < MAXN; i++)
		comp[i] = (lower_bound(ord, ord + ff, mx[i]) - ord);
	for (int i = n; i < n+m; i++)
		G[comp[i<<1]].push_back(comp[i<<1^1])
			, G[comp[i<<1^1]].push_back(comp[i<<1]);

	solve(0, 1);

	for (int i = 0; i < ff; i++)
		cout << ans[i] << " ";
	cout << "\n";
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long Long;

struct CentroidD{
    Long n, val_vis;
    vector< vector<Long> > adj;
    vector<Long> cparent, szt, vis, dist;
    vector< vector<Long> > cdTree;

    CentroidD(){}
    CentroidD(Long n) : n(n){
        val_vis = 0;
        vis.resize(n, -1);
        dist.resize(n, 0);
        cparent.resize(n, -1);
        szt.resize(n, 0);
        adj.resize(n);
        cdTree.resize(n);
    }

    void addEdge(Long u, Long v){
        adj[u].push_back(v);
        adj[v].push_back(u);
        return;
    }

    Long dfs(Long u, Long p){
        szt[u] = 1;
        vis[u] = val_vis;
        for(Long v : adj[u]){
            if(v != p && cparent[v] == -1 && vis[v] != val_vis) szt[u] += dfs(v,u);
        }
        return szt[u];
    }

    void decompotition(Long u, Long p, Long sz, Long pc, Long d){
        for(Long v : adj[u]){
            if(v != p && cparent[v] == -1 && (szt[v]<<1ll) > sz){
                decompotition(v,u,sz,pc,d);
                return;
            }
        }

        dist[u] = d;
        cparent[u] = pc;
        if(pc != -2){
            cdTree[u].push_back(pc);
            cdTree[pc].push_back(u);
        }
        for(Long v : adj[u]){
            if(cparent[v] == -1){
                dfs(v,-1);
                val_vis++;
                decompotition(v,-1,szt[v],u,d+1);
            }
        }
    }

    void build(Long u){
        dfs(u,-1);
        val_vis++;
        decompotition(u, -1, szt[u], -2, 1);
    }
};

const Long MX = 1e5 + 10;
multiset<Long> adj[MX];
vector<Long> bloq;
map< pair<Long,Long>,bool > used;
map< pair<Long,Long>, vector<Long> > ari;

void deleteEdge(Long u, Long v){
    auto it = adj[u].find(v);
    adj[u].erase(it);
    it = adj[v].find(u);
    adj[v].erase(it);
    return;
}

void add(Long u, Long v, Long id){
    auto it = used.find({u,v});
    if(it != used.end()){
        ari[{u,v}].push_back(id);
    }
    return;
}

void update(Long u, Long v, Long id){
    add(min(u,v),max(u,v),id);
    bloq.clear();
    while(u != v){
        bloq.push_back(u);
        auto it = adj[u].begin();
        Long x = *it;
        add(min(u,x),max(u,x),id);
        deleteEdge(x,u);
        u = x;
    }
    bloq.push_back(v);
    return;
}

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cout.precision(10);
    cout << fixed;

    Long n, m, x, y;
    cin >> n >> m;

    for(Long i = 1; i < n; i++){
        adj[i].insert(i+1);
        adj[i+1].insert(i);
    }
    adj[1].insert(n);
    adj[n].insert(1);

    for(Long i = 0; i < m; i++){
        cin >> x >> y;
        used[{min(x,y),max(x,y)}] = true;
        adj[x].insert(y);
        adj[y].insert(x);
        adj[x].insert(y);
        adj[y].insert(x);
    }

    if(m == 0){
        cout << 1 << "\n";
        return 0;
    }

    Long id = 0;
    vector< pair<vector<Long>,Long> > ord;
    for(Long u = n; u >= 1; u--){
        while(!adj[u].empty()){
            auto it = adj[u].begin();
            Long v = *it;
            deleteEdge(u,v);
            update(u,v,id);
            ord.push_back({bloq,id});
            id++;
        }
    }

    sort(ord.begin(),ord.end());

    CentroidD G;
    G = CentroidD(id);
    for(auto xx : ari){
        G.addEdge(xx.second[0],xx.second[1]);
    }
    G.build(0);

    for(Long i = 0; i < id; i++){
        cout << G.dist[ord[i].second] << " ";
    }
    cout << "\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef uint64_t ull;
typedef int64_t  ll;
const ll infll = 9223372036854775807LL;
#define PB push_back
#define MP make_pair
#define SZ(v) ((ll)(v).size())
#define FOR(i,a,b) for(ll i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(ll i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))

struct diag { ll a; ll b; ll sz; };
bool operator< (const diag &a, const diag &b) { return a.sz < b.sz || (a.sz == b.sz && a.a < b.a) || (a.sz == b.sz && a.a == b.a && a.b < b.b); }
struct region { ll idx; vector<ll> v; ll color;};
bool regionCmp (const region &a, const region &b) { return a.v[0] < b.v[0] || (a.v[0] == b.v[0] && a.v[1] < b.v[1]) || (a.v[0] == b.v[0] && a.v[1] == b.v[1] && a.v[2] < b.v[2]); }

// Dividing polygon into region tree
struct solver {
    ll n; ll m;
    vector<bool>       blocked;
    vector<vector<ll>> regTree;
    vector<vector<ll>> cdt;
    ll                 cdtRoot;
    vector<ll>         cdtNodeSize;
    vector<diag>       diags;
    vector<region>     regions;
    map<pair<ll,ll>,ll> diagToRegion;

    void read() {
        cin >> n >> m;
        diags.resize(m);
        REP(i,m) {
            ll a,b;
            cin >> a >> b;
            if (a > b) swap(a,b);
            diags[i].a = a;
            diags[i].b = b;
            diags[i].sz = min(b-a,n+a-b);
        }
    }

    void genRegionTree() {
        regTree.resize(m+1);
        regions.resize(m+1);
        REP(i,m+1) regions[i].idx = i;
        vector<ll> nxt(n+1);
        FORE(i,1,n) nxt[i] = i == n ? 1 : i+1;
        sort(diags.begin(),diags.end());
        ll regidx = 0;
        ll start,end,node,otherRegion;
        for (auto d : diags) {
            diagToRegion[{d.a,d.b}] = regidx;
            diagToRegion[{d.b,d.a}] = regidx;
            if (d.b - d.a == d.sz) { start=d.a; end=d.b; }
            else                   { start=d.b; end=d.a; }
            regions[regidx].v.PB(end);
            ll node = start;
            while (node != end) {
                regions[regidx].v.PB(node);
                ll nextNode = nxt[node];
                if (nextNode - node != 1 && !(node == n && nextNode == 1)) { // Found a diagonal, so need an edge to another region
                    otherRegion = diagToRegion[{node,nextNode}];
                    regTree[regidx].PB(otherRegion);
                    regTree[otherRegion].PB(regidx);
                }
                node = nextNode;
            }
            nxt[start] = end;
            regidx++;
        }
        // One more loop for the remaining region index;
        swap(start,end);
        regTree[regidx].PB(regidx-1);
        regTree[regidx-1].PB(regidx);
        node = start;
        regions[regidx].v.PB(end);
        while (node != end) {
            regions[regidx].v.PB(node);
            ll nextNode = nxt[node];
            if (nextNode - node != 1 && !(node == n && nextNode == 1)) { // Found a diagonal, so need an edge to another region
                otherRegion = diagToRegion[{node,nextNode}];
                regTree[regidx].PB(otherRegion);
                regTree[otherRegion].PB(regidx);
            }
            node = nextNode;
        }
    }

    void cdt1(ll nn, ll par) {
        cdtNodeSize[nn] = 1;
        for (auto nn2 : regTree[nn]) {
            if (nn2 == par || blocked[nn2]) continue;
            cdt1(nn2,nn);
            cdtNodeSize[nn] += cdtNodeSize[nn2];
        }
    }

    ll cdt2(ll nn, ll par, ll szlim) {
        for (auto nn2 : regTree[nn]) {
            if (nn2 == par || blocked[nn2]) continue;
            if (cdtNodeSize[nn2] > szlim) return cdt2(nn2, nn, szlim);
        }
        return nn;
    }

    void genCetroidDecompTree() {
        blocked.resize(m+1);
        cdtNodeSize.resize(m+1);
        cdt.resize(m+1);
        REP(i,m+1) blocked[i] = false;
        vector<pair<ll,ll>> st;
        st.PB({0,-1});
        while (!st.empty()) {
            ll nn = st.back().first;
            ll par = st.back().second;
            st.pop_back();
            if (blocked[nn]) continue;
            cdt1(nn,-1);
            ll centroid = cdt2(nn,-1,cdtNodeSize[nn]/2);
            blocked[centroid] = true;
            if (par == -1) cdtRoot = centroid;
            else           cdt[par].PB(centroid);
            for (auto nn2 : regTree[centroid]) { st.PB({nn2,centroid}); }
        }
    }

    void assignColors() {
        vector<pair<ll,ll>> st;
        st.PB({cdtRoot,1});
        while (!st.empty()) {
            ll nn = st.back().first;
            ll cc = st.back().second;
            st.pop_back();
            regions[nn].color = cc;
            for (auto nn2 : cdt[nn]) { st.PB({nn2,cc+1}); }
        }
    }

    // TODO: Need to sort based on importance now
    void dealWithImportance() {
        for (auto &r : regions) { sort(r.v.begin(),r.v.end()); reverse(r.v.begin(),r.v.end()); }
        sort(regions.begin(),regions.end(),regionCmp);
    }

    void solve() {
        read();
        if (m == 0) { cout << 1 << endl; return; }
        genRegionTree();
        genCetroidDecompTree();
        assignColors();
        dealWithImportance();
        for (auto r : regions) { cout << r.color << " "; }
        cout << endl;
    }

};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(15);
    solver s;
    //freopen("776F.in2","r",stdin);
    s.solve();
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef uint64_t ull;
typedef int64_t  ll;
const ll infll = 9223372036854775807LL;
#define PB push_back
#define MP make_pair
#define SZ(v) ((ll)(v).size())
#define FOR(i,a,b) for(ll i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(ll i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))

struct diag { ll a; ll b; ll sz; };
bool operator< (const diag &a, const diag &b) { return a.sz < b.sz || (a.sz == b.sz && a.a < b.a) || (a.sz == b.sz && a.a == b.a && a.b < b.b); }
struct region { ll idx; vector<ll> v; ll imp; ll color;};
bool operator< (const region &a, const region &b) { return a.imp < b.imp; }

// Dividing polygon into region tree
struct solver {
    ll n; ll m;
    vector<bool>       blocked;
    vector<vector<ll>> regTree;
    vector<vector<ll>> cdt;
    ll                 cdtRoot;
    vector<ll>         cdtNodeSize;
    vector<diag>       diags;
    vector<region>     regions;
    map<pair<ll,ll>,ll> diagToRegion;

    void read() {
        cin >> n >> m;
        diags.resize(m);
        REP(i,m) {
            ll a,b;
            cin >> a >> b;
            if (a > b) swap(a,b);
            diags[i].a = a;
            diags[i].b = b;
            diags[i].sz = min(b-a,n+a-b);
        }
    }

    void genRegionTree() {
        regTree.resize(m+1);
        regions.resize(m+1);
        REP(i,m+1) regions[i].idx = i;
        vector<ll> nxt(n+1);
        FORE(i,1,n) nxt[i] = i == n ? 1 : i+1;
        sort(diags.begin(),diags.end());
        ll regidx = 0;
        ll start,end,node,otherRegion;
        for (auto d : diags) {
            diagToRegion[{d.a,d.b}] = regidx;
            diagToRegion[{d.b,d.a}] = regidx;
            if (d.b - d.a == d.sz) { start=d.a; end=d.b; }
            else                   { start=d.b; end=d.a; }
            regions[regidx].v.PB(end);
            ll node = start;
            while (node != end) {
                regions[regidx].v.PB(node);
                ll nextNode = nxt[node];
                if (nextNode - node != 1 && !(node == n && nextNode == 1)) { // Found a diagonal, so need an edge to another region
                    otherRegion = diagToRegion[{node,nextNode}];
                    regTree[regidx].PB(otherRegion);
                    regTree[otherRegion].PB(regidx);
                }
                node = nextNode;
            }
            nxt[start] = end;
            regidx++;
        }
        // One more loop for the remaining region index;
        swap(start,end);
        regTree[regidx].PB(regidx-1);
        regTree[regidx-1].PB(regidx);
        node = start;
        regions[regidx].v.PB(end);
        while (node != end) {
            regions[regidx].v.PB(node);
            ll nextNode = nxt[node];
            if (nextNode - node != 1 && !(node == n && nextNode == 1)) { // Found a diagonal, so need an edge to another region
                otherRegion = diagToRegion[{node,nextNode}];
                regTree[regidx].PB(otherRegion);
                regTree[otherRegion].PB(regidx);
            }
            node = nextNode;
        }
    }

    void cdt1(ll nn, ll par) {
        cdtNodeSize[nn] = 1;
        for (auto nn2 : regTree[nn]) {
            if (nn2 == par || blocked[nn2]) continue;
            cdt1(nn2,nn);
            cdtNodeSize[nn] += cdtNodeSize[nn2];
        }
    }

    ll cdt2(ll nn, ll par, ll szlim) {
        for (auto nn2 : regTree[nn]) {
            if (nn2 == par || blocked[nn2]) continue;
            if (cdtNodeSize[nn2] > szlim) return cdt2(nn2, nn, szlim);
        }
        return nn;
    }

    void genCetroidDecompTree() {
        blocked.resize(m+1);
        cdtNodeSize.resize(m+1);
        cdt.resize(m+1);
        REP(i,m+1) blocked[i] = false;
        vector<pair<ll,ll>> st;
        st.PB({0,-1});
        while (!st.empty()) {
            ll nn = st.back().first;
            ll par = st.back().second;
            st.pop_back();
            if (blocked[nn]) continue;
            cdt1(nn,-1);
            ll centroid = cdt2(nn,-1,cdtNodeSize[nn]/2);
            blocked[centroid] = true;
            if (par == -1) cdtRoot = centroid;
            else           cdt[par].PB(centroid);
            for (auto nn2 : regTree[centroid]) { st.PB({nn2,centroid}); }
        }
    }

    void assignColors() {
        vector<pair<ll,ll>> st;
        st.PB({cdtRoot,1});
        while (!st.empty()) {
            ll nn = st.back().first;
            ll cc = st.back().second;
            st.pop_back();
            regions[nn].color = cc;
            for (auto nn2 : cdt[nn]) { st.PB({nn2,cc+1}); }
        }
    }

    void dealWithImportance() {
        for (auto &r : regions) {
            r.imp = 0;
            for (auto &&nn : r.v) r.imp = r.imp | (1 << nn);
        }
        sort(regions.begin(),regions.end());
    }

    void solve() {
        read();
        genRegionTree();
        genCetroidDecompTree();
        assignColors();
        dealWithImportance();
        for (auto r : regions) { cout << r.color << " "; }
        cout << endl;
    }

};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(15);
    solver s;
    //freopen("776F.in2","r",stdin);
    s.solve();
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef uint64_t ull;
typedef int64_t  ll;
const ll infll = 9223372036854775807LL;
#define PB push_back
#define MP make_pair
#define SZ(v) ((ll)(v).size())
#define FOR(i,a,b) for(ll i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(ll i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))

struct diag { ll a; ll b; ll sz; };
bool operator< (const diag &a, const diag &b) { return a.sz < b.sz || (a.sz == b.sz && a.a < b.a) || (a.sz == b.sz && a.a == b.a && a.b < b.b); }
struct region { ll idx; vector<ll> v; ll imp; ll color;};
bool operator< (const region &a, const region &b) { return a.imp < b.imp; }

// Dividing polygon into region tree
struct solver {
    ll n; ll m;
    vector<bool>       blocked;
    vector<vector<ll>> regTree;
    vector<vector<ll>> cdt;
    ll                 cdtRoot;
    vector<ll>         cdtNodeSize;
    vector<diag>       diags;
    vector<region>     regions;
    map<pair<ll,ll>,ll> diagToRegion;

    void read() {
        cin >> n >> m;
        diags.resize(m);
        REP(i,m) {
            ll a,b;
            cin >> a >> b;
            if (a > b) swap(a,b);
            diags[i].a = a;
            diags[i].b = b;
            diags[i].sz = min(b-a,n+a-b);
        }
    }

    void genRegionTree() {
        regTree.resize(m+1);
        regions.resize(m+1);
        REP(i,m+1) regions[i].idx = i;
        vector<ll> nxt(n+1);
        FORE(i,1,n) nxt[i] = i == n ? 1 : i+1;
        sort(diags.begin(),diags.end());
        ll regidx = 0;
        ll start,end,node,otherRegion;
        for (auto d : diags) {
            diagToRegion[{d.a,d.b}] = regidx;
            diagToRegion[{d.b,d.a}] = regidx;
            if (d.b - d.a == d.sz) { start=d.a; end=d.b; }
            else                   { start=d.b; end=d.a; }
            regions[regidx].v.PB(end);
            ll node = start;
            while (node != end) {
                regions[regidx].v.PB(node);
                ll nextNode = nxt[node];
                if (nextNode - node != 1 && !(node == n && nextNode == 1)) { // Found a diagonal, so need an edge to another region
                    otherRegion = diagToRegion[{node,nextNode}];
                    regTree[regidx].PB(otherRegion);
                    regTree[otherRegion].PB(regidx);
                }
                node = nextNode;
            }
            nxt[start] = end;
            regidx++;
        }
        // One more loop for the remaining region index;
        swap(start,end);
        regTree[regidx].PB(regidx-1);
        regTree[regidx-1].PB(regidx);
        node = start;
        regions[regidx].v.PB(end);
        while (node != end) {
            regions[regidx].v.PB(node);
            ll nextNode = nxt[node];
            if (nextNode - node != 1 && !(node == n && nextNode == 1)) { // Found a diagonal, so need an edge to another region
                otherRegion = diagToRegion[{node,nextNode}];
                regTree[regidx].PB(otherRegion);
                regTree[otherRegion].PB(regidx);
            }
            node = nextNode;
        }
    }

    void cdt1(ll nn, ll par) {
        cdtNodeSize[nn] = 1;
        for (auto nn2 : regTree[nn]) {
            if (nn2 == par || blocked[nn2]) continue;
            cdt1(nn2,nn);
            cdtNodeSize[nn] += cdtNodeSize[nn2];
        }
    }

    ll cdt2(ll nn, ll par, ll szlim) {
        for (auto nn2 : regTree[nn]) {
            if (nn2 == par || blocked[nn2]) continue;
            if (cdtNodeSize[nn2] > szlim) return cdt2(nn2, nn, szlim);
        }
        return nn;
    }

    void genCetroidDecompTree() {
        blocked.resize(m+1);
        cdtNodeSize.resize(m+1);
        cdt.resize(m+1);
        REP(i,m+1) blocked[i] = false;
        vector<pair<ll,ll>> st;
        st.PB({0,-1});
        while (!st.empty()) {
            ll nn = st.back().first;
            ll par = st.back().second;
            st.pop_back();
            if (blocked[nn]) continue;
            cdt1(nn,-1);
            ll centroid = cdt2(nn,-1,cdtNodeSize[nn]/2);
            blocked[centroid] = true;
            if (par == -1) cdtRoot = centroid;
            else           cdt[par].PB(centroid);
            for (auto nn2 : regTree[centroid]) { st.PB({nn2,centroid}); }
        }
    }

    void assignColors() {
        vector<pair<ll,ll>> st;
        st.PB({cdtRoot,1});
        while (!st.empty()) {
            ll nn = st.back().first;
            ll cc = st.back().second;
            st.pop_back();
            regions[nn].color = cc;
            for (auto nn2 : cdt[nn]) { st.PB({nn2,cc+1}); }
        }
    }

    void dealWithImportance() {
        for (auto &r : regions) {
            r.imp = 0;
            for (auto &&nn : r.v) r.imp = r.imp | (1 << nn);
        }
        sort(regions.begin(),regions.end());
    }

    void solve() {
        read();
        if (m == 0) { cout << 1 << endl; return; }
        genRegionTree();
        genCetroidDecompTree();
        assignColors();
        dealWithImportance();
        for (auto r : regions) { cout << r.color << " "; }
        cout << endl;
    }

};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(15);
    solver s;
    //freopen("776F.in2","r",stdin);
    s.solve();
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

#define fi first
#define se second
#define mp make_pair
#define fastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

const int N = (int)1e5 + 9;
vector<int> st[N];

map<pii, vector<int>> con;

vector<int> T[N];
bool use[N];
int dep[N];
int subt[N];

void dfs(int u, int par){
  subt[u]=1;
  for(auto x : T[u]){
    if(x==par || use[x]) continue;
    dfs(x, u);
    subt[u] += subt[x];
  }
}

int fin(int node){
  dfs(node, -1);
  int cur = node;
  int pi = -1;
  bool ok = true;
  while(ok){
    ok=false;
    for(auto x : T[cur]){
      if(x == pi || use[x]) continue;
      if(2*subt[x] >= subt[node]){
        pi=cur;
        cur=x;
        ok=true;
        break;
      }
    }
  }
  return cur;
}

void dec(int node, int di){
  node = fin(node);
  use[node]=true;
  dep[node]=di;
  for(auto x : T[node]){
    if(!use[x])
      dec(x, di+1);
  }
}

int main(){
  fastIO;
  int n, m;
  cin >> n >> m;
  int a[m], b[m];
  pii dd[m];
  int low;
  for(int i = 0 ; i < m ; i ++ ){
    cin >> a[i] >> b[i];
    if(a[i] > b[i]) swap(a[i], b[i]);
    low = min(b[i]-a[i]-1,n-(b[i]-a[i]+1));
    dd[i] = mp(low, i);
  }
  sort(dd, dd + m);
  set<int> rem;
  for(int i = 1; i <= n; i ++ )
    rem.insert(i);
  int q = m + 1;
  int li, ri;
  for(int i = 0 ; i < m ; i ++ ){
    li = a[dd[i].se];
    ri = b[dd[i].se];
    if(ri - li - 1 <= n - (ri - li + 1)){
      st[i].push_back(li);
      st[i].push_back(ri);
      auto it = rem.upper_bound(li);
      while(*it < ri){
        st[i].push_back(*it);
        it = rem.erase(it);
      }
    }
    else{
      st[i].push_back(li);
      st[i].push_back(ri);
      auto it = rem.lower_bound(li);
      while(1){
        if(it == rem.begin()){
          it = rem.end();
          --it;
        }
        else{
          --it;
        }
        if(*it == ri) break;
        st[i].push_back(*it);
      }
      for(auto x : st[i])
        if(x!=li && x!=ri) rem.erase(x);
    }
  }
  for(auto x : rem) st[m].push_back(x);
  for(int i = 0 ;i <= m ; i ++ ){
    sort(st[i].begin(), st[i].end());
    reverse(st[i].begin(), st[i].end());
  }
  sort(st, st + q);
  int k;
  int u, v;
  for(int i = 0 ; i < q; i ++ ){
    k = st[i].size();
    for(int j = 0 ; j < k; j ++ ){
      u = st[i][j];
      v = st[i][(j+1)%k];
      if(u > v) swap(u,v);
      con[mp(u,v)].push_back(i);
    }
  }
  for(auto x : con){
    if(x.se.size() == 2){
      u = x.se[0];
      v = x.se[1];
      T[u].push_back(v);
      T[v].push_back(u);
    }
  }
  dec(0,1);
  for(int i = 0 ; i < q; i ++ )
    cout << dep[i] << " ";
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define REP(i, n) for(int i = 0; i < (n); i++)

int n, m;
vector <pair <int, int> > dij;
vector <vector <int> > sus;

map <pair <int, int>, int> bio;

vector <vector <int> > graf;
vector <pair <pair <int, int>, int> > najveci;
int brojac = 0;

vector <bool> obradeni;
vector <int> vel;

int rek(int cvor, int par) {
	int ret = 0;
	for(int djeca : graf[cvor]) {
		if(obradeni[djeca] || djeca == par) continue;
		ret += rek(djeca, cvor);
	}
	return vel[cvor] = ret + 1;
}

void dek(int cvor, int dub) {
	int tr_vel = vel[cvor] = rek(cvor, -1);
	bool nasao = 0;
	int par = -1;
	while(!nasao) {
		nasao = 1;
		for(int djeca : graf[cvor]) {
			if(obradeni[djeca] || djeca == par) continue;
			if(vel[djeca] > tr_vel / 2) {
				nasao = 0;
				par = cvor;
				cvor = djeca;
				break;
			}
		}
	}
	obradeni[cvor] = 1;
	najveci[cvor].second = dub;
	for(int djeca : graf[cvor]) {
		if(!obradeni[djeca]) dek(djeca, dub + 1);
	}
	return;
}

int main() {
	scanf("%d%d", &n, &m);
	if(m == 0) {
		printf("%d\n", 1);
		exit(0);
	}
	graf.resize(m + 1, vector <int>());
	najveci.resize(m + 1, make_pair(make_pair(-1, -1), 0));
	obradeni.resize(m + 1, 0);
	vel.resize(m + 1);
	sus.insert(sus.begin(), n, vector <int>());
	dij.resize(m);
	int a, b;
	REP(i, n - 1) {
		sus[i].push_back(i + 1);
		sus[i + 1].push_back(i);
	}
	sus[0].push_back(n - 1);
	sus[n - 1].push_back(0);
	REP(i, m) {
		scanf("%d%d", &a, &b);
		a--; b--;
		dij[i] = make_pair(a, b);
		sus[a].push_back(b);
		sus[b].push_back(a);
		bio[make_pair(a, b)] = bio[make_pair(b, a)] = -1;
	}
	REP(i, n) sort(sus[i].begin(), sus[i].end());
	REP(j, 2) {
		REP(i, m) {
			if(bio[dij[i]] == -1) {
				int zadnji = dij[i].first, tr = dij[i].second, prosli = dij[i].first;
				do {
					if(tr > najveci[brojac].first.first) {
						najveci[brojac].first.second = najveci[brojac].first.first;
						najveci[brojac].first.first = tr;
					}
					else if(tr > najveci[brojac].first.second) najveci[brojac].first.second = tr;
					if(abs(prosli - tr) != 1 && abs(prosli - tr) != n - 1) {
						bio[make_pair(prosli, tr)] = brojac;
						if(bio[make_pair(tr, prosli)] != -1) {
							graf[brojac].push_back(bio[make_pair(tr, prosli)]);
							graf[bio[make_pair(tr, prosli)]].push_back(brojac);
						}
					}
					int pom = tr;
					vector <int> :: iterator it = lower_bound(sus[tr].begin(), sus[tr].end(), prosli);
					it++;
					if(it == sus[tr].end()) it = sus[tr].begin();
					tr = *it;
					prosli = pom;
				} while(prosli != zadnji);
				brojac++;
			}
		}
		REP(i, m) swap(dij[i].first, dij[i].second);
	}
	dek(0, 1);
	sort(najveci.begin(), najveci.end());
	REP(i, m + 1) printf("%d ", najveci[i].second);
	printf("\n");
	return 0;
}


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<string>
#include<iostream>
#include<ext/pb_ds/priority_queue.hpp>
#include<queue>
#include<stack>
#define pb push_back
#define all(a) a.begin(),a.end()
#define pointtype double
#define pointtype_INT 0
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
typedef unsigned uint;
typedef unsigned long long uLL;
const double pi=acos(-1);
template<class T>
void Read(T &x){
	char c;
	bool f(0);
	while(c=getchar(),c!=EOF){
		if(c=='-')
			f=1;
		else if(c>='0'&&c<='9'){
			x=c-'0';
			while(c=getchar(),c>='0'&&c<='9')
				x=x*10+c-'0';
			ungetc(c,stdin);
			if(f)
				x=-x;
			return;
		}
	}
}
struct point{
	pointtype x,y;
	inline point(){
	}
	inline point(pointtype x,pointtype y=0):x(x),y(y){
	}
	inline point operator+(const point &a)const{
		return point(x+a.x,y+a.y);
	}
	inline point operator+=(const point &a){
		return *this=*this+a;
	}
	inline point operator-(const point &a)const{
		return point(x-a.x,y-a.y);
	}
	inline point operator-=(const point &a){
		return *this=*this-a;
	}
	inline bool operator<(const point &b)const{
		if(x==b.x)
			return y<b.y;
		return x<b.x;
	}
	inline bool operator==(const point &b)const{
		return x==b.x&&y==b.y;
	}
	#if pointtype_INT==1
		inline point operator*(const point &a)const{
			return point(1ll*x*a.x-1ll*y*a.y,1ll*x*a.y+1ll*y*a.x);
		}
		inline friend LL cross(const point &a,const point &b){
			return 1ll*a.x*b.y-1ll*a.y*b.x;
		}
		inline friend LL dot(const point &a,const point &b){
			return 1ll*a.x*b.x+1ll*a.y*b.y;
		}
	#else
		inline point operator*(const point &a)const{
			return point(x*a.x-y*a.y,x*a.y+y*a.x);
		}
		inline friend pointtype cross(const point &a,const point &b){
			return a.x*b.y-a.y*b.x;
		}
		inline friend pointtype dot(const point &a,const point &b){
			return a.x*b.x+a.y*b.y;
		}
	#endif
};
template<class T,class T2>
struct hashnode{
	T val;
	T2 v;
	hashnode *next;
};
template<class T,class T2>
inline int& addhash(int u,const T &val,T2 *&ecnt,T2 **adj){
	T2 *p=++ecnt;
	p->val=val;
	p->v=0;
	p->next=adj[u];
	adj[u]=p;
	return p->v;
}
template<class T,class T2,int MOD,int ss>
class hash_table{
	hashnode<T,T2>*adj[MOD],edge[ss+10],*ecnt;
	int sz;
	public:
	inline int Get_val(int x){
		return x%MOD;
	}
	#if pointtype_INT==1
		inline int Get_val(point x){
			return (x.x*998244353ll+x.y)%MOD;
		}
	#endif
	inline hash_table():ecnt(edge),sz(0){
		for(int i=0;i<MOD;i++)
			adj[i]=0;
	}
	inline int size(){
		return sz;
	}
	inline hashnode<T,T2>* hash(const T &x){
		int t=Get_val(x);
		for(hashnode<T,T2> *p=adj[t];p;p=p->next)
			if(p->val==x)
				return p;
		return 0;
	}
	inline int &operator[](const T &x){
		hashnode<T,T2> *p=hash(x);
		if(p)
			return p->v;
		return ++sz,addhash(Get_val(x)%MOD,x,ecnt,adj);
	}
	inline bool count(const T &x){
		return hash(x);
	}
	inline void clear(){
		ecnt=edge;
		int t=MOD>>2<<2,i;
		for(i=0;i<t;i+=4){
			adj[i]=0;
			adj[i+1]=0;
			adj[i+2]=0;
			adj[i+3]=0;
		}
		for(;i<MOD;i++)
			adj[i]=0;
		sz=0;
	}
};
template<class T,int len>
struct polynomial{
	T a[len];
	inline void clear(){
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			a[i]=0;
			a[i+1]=0;
			a[i+2]=0;
			a[i+3]=0;
		}
		for(;i<len;i++)
			a[i]=0;
	}
	inline polynomial operator+(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]+b.a[i];
			c.a[i+1]=a[i+1]+b.a[i+1];
			c.a[i+2]=a[i+2]+b.a[i+2];
			c.a[i+3]=a[i+3]+b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]+b.a[i];
		return c;
	}
	inline polynomial operator+=(const polynomial &b){
		return *this=*this+b;
	}
	inline polynomial operator-(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]-b.a[i];
			c.a[i+1]=a[i+1]-b.a[i+1];
			c.a[i+2]=a[i+2]-b.a[i+2];
			c.a[i+3]=a[i+3]-b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]-b.a[i];
		return c;
	}
	inline polynomial operator-=(const polynomial &b){
		return *this=*this-b;
	}
};
//template
#define MAXN 100000
pii a[MAXN*2+10];
int n,m,d[MAXN+10],cnt,tp,b[MAXN+10],st[MAXN+10],size[MAXN+10],mxs[MAXN+10],col[MAXN+10],rt,pos[MAXN+10];
bool vis[MAXN+10];
vector<int>pt[MAXN+10],g[MAXN+10];
void find_center(int u,int fa,int tot,int &heavy){
	size[u]=1;
	mxs[u]=0;
	for(auto v:g[u]){
		if(!col[v]&&v!=fa){
			find_center(v,u,tot,heavy);
			size[u]+=size[v];
			mxs[u]=max(mxs[u],size[v]);
		}
	}
	mxs[u]=max(mxs[u],tot-size[u]);
	if(mxs[u]<mxs[heavy])
		heavy=u;
}
void solve(int u,int tot,int c){
	int heavy(0);
	find_center(u,0,tot,heavy);
	col[heavy]=c;
	c++;
	for(auto v:g[heavy]){
		if(!col[v]){
			if(size[v]>size[heavy])
				solve(v,tot-size[heavy],c);
			else
				solve(v,size[v],c);
		}
	}
}
int main()
{
	Read(n),Read(m);
	int i,x,y,j;
	for(i=1;i<=m;i++){
		Read(x),Read(y);
		if(x>y)
			swap(x,y);
		if(y-x>n/2)
			swap(x,y);
		a[i]=pii(x,y);
		a[i+m]=pii(y,x);
		if(x<y)
			d[x+1]++,d[y]--;
		else
			d[x+1]++,d[1]++,d[y]--;
	}
	m*=2;
	for(i=1;i<=n;i++){
		d[i]+=d[i-1];
		if(!d[i]){
			rt=i;
			break;
		}
	}
	j=rt;
	do{
		pos[j]=++cnt;
		if(++j>n)
			j=1;
	}while(j!=rt);
	sort(a+1,a+m+1,[](auto x,auto y){return x.first==y.first?pos[x.second]<pos[y.second]:pos[x.first]<pos[y.first];});
	st[tp=1]=cnt=1;
	i=rt;
	j=1;
	do{
		pt[st[tp]].pb(i);
		for(;j<=m&&a[j].first==i;j++){
			if(pos[a[j].second]>pos[a[j].first]){
				g[st[tp]].pb(++cnt);
				g[cnt].pb(st[tp]);
				st[++tp]=cnt;
				pt[cnt].pb(i);
			}
			else{
				g[st[tp]].pb(st[tp-1]);
				g[st[tp-1]].pb(st[tp]);
				tp--;
				pt[st[tp]].pb(i);
			}
		}
		if(++i>n)
			i=1;
	}while(i!=rt);
	for(i=1;i<=cnt;i++){
		sort(all(pt[i]),greater<int>());
		b[i]=i;
	}
	for(i=1;i<=n;i++){
		sort(all(g[i]));
		g[i].erase(unique(all(g[i])),g[i].end());
	}
	mxs[0]=0x7fffffff;
	solve(1,n,1);
	sort(b+1,b+cnt+1,[](int x,int y){return pt[x]<pt[y];});
	for(i=1;i<=cnt;i++)
		printf("%d ",col[b[i]]);
}


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<ext/pb_ds/priority_queue.hpp>
#include<queue>
#include<stack>
#define pb push_back
#define all(a) a.begin(),a.end()
#define pointtype double
#define pointtype_INT 0
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
typedef unsigned uint;
typedef unsigned long long uLL;
const double pi=acos(-1);
template<class T>
void Read(T &x){
	char c;
	bool f(0);
	while(c=getchar(),c!=EOF){
		if(c=='-')
			f=1;
		else if(c>='0'&&c<='9'){
			x=c-'0';
			while(c=getchar(),c>='0'&&c<='9')
				x=x*10+c-'0';
			ungetc(c,stdin);
			if(f)
				x=-x;
			return;
		}
	}
}
struct point{
	pointtype x,y;
	inline point(){
	}
	inline point(pointtype x,pointtype y=0):x(x),y(y){
	}
	inline point operator+(const point &a)const{
		return point(x+a.x,y+a.y);
	}
	inline point operator+=(const point &a){
		return *this=*this+a;
	}
	inline point operator-(const point &a)const{
		return point(x-a.x,y-a.y);
	}
	inline point operator-=(const point &a){
		return *this=*this-a;
	}
	inline bool operator<(const point &b)const{
		if(x==b.x)
			return y<b.y;
		return x<b.x;
	}
	inline bool operator==(const point &b)const{
		return x==b.x&&y==b.y;
	}
	#if pointtype_INT==1
		inline point operator*(const point &a)const{
			return point(1ll*x*a.x-1ll*y*a.y,1ll*x*a.y+1ll*y*a.x);
		}
		inline friend LL cross(const point &a,const point &b){
			return 1ll*a.x*b.y-1ll*a.y*b.x;
		}
		inline friend LL dot(const point &a,const point &b){
			return 1ll*a.x*b.x+1ll*a.y*b.y;
		}
	#else
		inline point operator*(const point &a)const{
			return point(x*a.x-y*a.y,x*a.y+y*a.x);
		}
		inline friend pointtype cross(const point &a,const point &b){
			return a.x*b.y-a.y*b.x;
		}
		inline friend pointtype dot(const point &a,const point &b){
			return a.x*b.x+a.y*b.y;
		}
	#endif
};
template<class T,class T2>
struct hashnode{
	T val;
	T2 v;
	hashnode *next;
};
template<class T,class T2>
inline int& addhash(int u,const T &val,T2 *&ecnt,T2 **adj){
	T2 *p=++ecnt;
	p->val=val;
	p->v=0;
	p->next=adj[u];
	adj[u]=p;
	return p->v;
}
template<class T,class T2,int MOD,int ss>
class hash_table{
	hashnode<T,T2>*adj[MOD],edge[ss+10],*ecnt;
	int sz;
	public:
	inline int Get_val(int x){
		return x%MOD;
	}
	#if pointtype_INT==1
		inline int Get_val(point x){
			return (x.x*998244353ll+x.y)%MOD;
		}
	#endif
	inline hash_table():ecnt(edge),sz(0){
		for(int i=0;i<MOD;i++)
			adj[i]=0;
	}
	inline int size(){
		return sz;
	}
	inline hashnode<T,T2>* hash(const T &x){
		int t=Get_val(x);
		for(hashnode<T,T2> *p=adj[t];p;p=p->next)
			if(p->val==x)
				return p;
		return 0;
	}
	inline int &operator[](const T &x){
		hashnode<T,T2> *p=hash(x);
		if(p)
			return p->v;
		return ++sz,addhash(Get_val(x)%MOD,x,ecnt,adj);
	}
	inline bool count(const T &x){
		return hash(x);
	}
	inline void clear(){
		ecnt=edge;
		int t=MOD>>2<<2,i;
		for(i=0;i<t;i+=4){
			adj[i]=0;
			adj[i+1]=0;
			adj[i+2]=0;
			adj[i+3]=0;
		}
		for(;i<MOD;i++)
			adj[i]=0;
		sz=0;
	}
};
template<class T,int len>
struct polynomial{
	T a[len];
	inline void clear(){
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			a[i]=0;
			a[i+1]=0;
			a[i+2]=0;
			a[i+3]=0;
		}
		for(;i<len;i++)
			a[i]=0;
	}
	inline polynomial operator+(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]+b.a[i];
			c.a[i+1]=a[i+1]+b.a[i+1];
			c.a[i+2]=a[i+2]+b.a[i+2];
			c.a[i+3]=a[i+3]+b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]+b.a[i];
		return c;
	}
	inline polynomial operator+=(const polynomial &b){
		return *this=*this+b;
	}
	inline polynomial operator-(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]-b.a[i];
			c.a[i+1]=a[i+1]-b.a[i+1];
			c.a[i+2]=a[i+2]-b.a[i+2];
			c.a[i+3]=a[i+3]-b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]-b.a[i];
		return c;
	}
	inline polynomial operator-=(const polynomial &b){
		return *this=*this-b;
	}
};
//template
#define MAXK 123
LL k,a,n,d,g[MAXK+10],fac[MAXK+10],h[MAXK+10],T,sf[MAXK+10],fr[MAXK+10];
#define MOD 1234567891
void read(){
	Read(k),Read(a),Read(n),Read(d);
}
LL quick_pow(LL a,LL b){
	int ret(1);
	while(b){
		if(b&1)
			ret=1ll*ret*a%MOD;
		a=1ll*a*a%MOD;
		b>>=1;
	}
	return ret;
}
LL f(LL n){
	LL i,ret(0);
	for(i=1;i<=n;i++)
		ret=(ret+quick_pow(i,k))%MOD;
	return ret;
}
LL lagrange(LL X,LL len,LL *a){
	LL i,tt,ret(0);
	fr[0]=1;
	for(i=0;i<=len;i++)
		fr[i+1]=1ll*fr[i]*(X-i)%MOD;
	sf[len+1]=1;
	for(i=len;i>=0;i--)
		sf[i]=1ll*sf[i+1]*(X-i)%MOD;
	*fac=1;
	for(i=1;i<=len;i++)
		fac[i]=1ll*fac[i-1]*i%MOD;
	for(i=0;i<=len;i++){
		tt=1ll*fr[i]*sf[i+1]%MOD*quick_pow(fac[i],MOD-2)%MOD*quick_pow((i&1)?MOD-fac[len-i]:fac[len-i],MOD-2)%MOD*a[i]%MOD;
		ret=(ret+tt)%MOD;
	}
	return (ret%MOD+MOD)%MOD;
}
void solve(){
	LL i;
	for(i=1;i<=k+2;i++)
		g[i]=(g[i-1]+f(i))%MOD;
	h[0]=lagrange(a,k+2,g);
	for(i=1;i<=k+3;i++)
		h[i]=(h[i-1]+lagrange((a+i*d)%MOD,k+2,g))%MOD;
	printf("%lld\n",lagrange(n,k+3,h));
}


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<string>
#include<iostream>
#include<ext/pb_ds/priority_queue.hpp>
#include<queue>
#include<stack>
#define pb push_back
#define all(a) a.begin(),a.end()
#define pointtype double
#define pointtype_INT 0
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
typedef unsigned uint;
typedef unsigned long long uLL;
const double pi=acos(-1);
template<class T>
void Read(T &x){
	char c;
	bool f(0);
	while(c=getchar(),c!=EOF){
		if(c=='-')
			f=1;
		else if(c>='0'&&c<='9'){
			x=c-'0';
			while(c=getchar(),c>='0'&&c<='9')
				x=x*10+c-'0';
			ungetc(c,stdin);
			if(f)
				x=-x;
			return;
		}
	}
}
struct point{
	pointtype x,y;
	inline point(){
	}
	inline point(pointtype x,pointtype y=0):x(x),y(y){
	}
	inline point operator+(const point &a)const{
		return point(x+a.x,y+a.y);
	}
	inline point operator+=(const point &a){
		return *this=*this+a;
	}
	inline point operator-(const point &a)const{
		return point(x-a.x,y-a.y);
	}
	inline point operator-=(const point &a){
		return *this=*this-a;
	}
	inline bool operator<(const point &b)const{
		if(x==b.x)
			return y<b.y;
		return x<b.x;
	}
	inline bool operator==(const point &b)const{
		return x==b.x&&y==b.y;
	}
	#if pointtype_INT==1
		inline point operator*(const point &a)const{
			return point(1ll*x*a.x-1ll*y*a.y,1ll*x*a.y+1ll*y*a.x);
		}
		inline friend LL cross(const point &a,const point &b){
			return 1ll*a.x*b.y-1ll*a.y*b.x;
		}
		inline friend LL dot(const point &a,const point &b){
			return 1ll*a.x*b.x+1ll*a.y*b.y;
		}
	#else
		inline point operator*(const point &a)const{
			return point(x*a.x-y*a.y,x*a.y+y*a.x);
		}
		inline friend pointtype cross(const point &a,const point &b){
			return a.x*b.y-a.y*b.x;
		}
		inline friend pointtype dot(const point &a,const point &b){
			return a.x*b.x+a.y*b.y;
		}
	#endif
};
template<class T,class T2>
struct hashnode{
	T val;
	T2 v;
	hashnode *next;
};
template<class T,class T2>
inline int& addhash(int u,const T &val,T2 *&ecnt,T2 **adj){
	T2 *p=++ecnt;
	p->val=val;
	p->v=0;
	p->next=adj[u];
	adj[u]=p;
	return p->v;
}
template<class T,class T2,int MOD,int ss>
class hash_table{
	hashnode<T,T2>*adj[MOD],edge[ss+10],*ecnt;
	int sz;
	public:
	inline int Get_val(int x){
		return x%MOD;
	}
	#if pointtype_INT==1
		inline int Get_val(point x){
			return (x.x*998244353ll+x.y)%MOD;
		}
	#endif
	inline hash_table():ecnt(edge),sz(0){
		for(int i=0;i<MOD;i++)
			adj[i]=0;
	}
	inline int size(){
		return sz;
	}
	inline hashnode<T,T2>* hash(const T &x){
		int t=Get_val(x);
		for(hashnode<T,T2> *p=adj[t];p;p=p->next)
			if(p->val==x)
				return p;
		return 0;
	}
	inline int &operator[](const T &x){
		hashnode<T,T2> *p=hash(x);
		if(p)
			return p->v;
		return ++sz,addhash(Get_val(x)%MOD,x,ecnt,adj);
	}
	inline bool count(const T &x){
		return hash(x);
	}
	inline void clear(){
		ecnt=edge;
		int t=MOD>>2<<2,i;
		for(i=0;i<t;i+=4){
			adj[i]=0;
			adj[i+1]=0;
			adj[i+2]=0;
			adj[i+3]=0;
		}
		for(;i<MOD;i++)
			adj[i]=0;
		sz=0;
	}
};
template<class T,int len>
struct polynomial{
	T a[len];
	inline void clear(){
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			a[i]=0;
			a[i+1]=0;
			a[i+2]=0;
			a[i+3]=0;
		}
		for(;i<len;i++)
			a[i]=0;
	}
	inline polynomial operator+(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]+b.a[i];
			c.a[i+1]=a[i+1]+b.a[i+1];
			c.a[i+2]=a[i+2]+b.a[i+2];
			c.a[i+3]=a[i+3]+b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]+b.a[i];
		return c;
	}
	inline polynomial operator+=(const polynomial &b){
		return *this=*this+b;
	}
	inline polynomial operator-(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]-b.a[i];
			c.a[i+1]=a[i+1]-b.a[i+1];
			c.a[i+2]=a[i+2]-b.a[i+2];
			c.a[i+3]=a[i+3]-b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]-b.a[i];
		return c;
	}
	inline polynomial operator-=(const polynomial &b){
		return *this=*this-b;
	}
};
//template
#define MAXN 100000
pii a[MAXN*2+10];
int n,m,d[MAXN+10],cnt,tp,b[MAXN+10],st[MAXN+10],size[MAXN+10],mxs[MAXN+10],col[MAXN+10],rt,pos[MAXN+10];
bool vis[MAXN+10];
vector<int>pt[MAXN+10],g[MAXN+10];
void find_center(int u,int fa,int tot,int &heavy){
	size[u]=1;
	for(auto v:g[u]){
		if(!col[v]&&v!=fa){
			find_center(v,u,tot,heavy);
			size[u]+=size[v];
			mxs[u]=max(mxs[u],size[v]);
		}
	}
	mxs[u]=max(mxs[u],tot-size[u]);
	if(mxs[u]<mxs[heavy])
		heavy=u;
}
void solve(int u,int tot,int c){
	int heavy(0);
	find_center(u,0,tot,heavy);
	col[heavy]=c;
	c++;
	for(auto v:g[heavy]){
		if(!col[v]){
			if(size[v]>size[heavy])
				solve(v,tot-size[heavy],c);
			else
				solve(v,size[v],c);
		}
	}
}
int main()
{
	Read(n),Read(m);
	int i,x,y,j;
	for(i=1;i<=m;i++){
		Read(x),Read(y);
		if(x>y)
			swap(x,y);
		if(y-x>n/2)
			swap(x,y);
		a[i]=pii(x,y);
		a[i+m]=pii(y,x);
		if(x<y)
			d[x+1]++,d[y]--;
		else
			d[x+1]++,d[1]++,d[y]--;
	}
	m*=2;
	for(i=1;i<=n;i++){
		d[i]+=d[i-1];
		if(!d[i]){
			rt=i;
			break;
		}
	}
	j=rt;
	do{
		pos[j]=++cnt;
		if(++j>n)
			j=1;
	}while(j!=rt);
	sort(a+1,a+m+1,[](auto x,auto y){return x.first==y.first?pos[x.second]<pos[y.second]:pos[x.first]<pos[y.first];});
	st[tp=1]=cnt=1;
	i=rt;
	j=1;
	do{
		pt[st[tp]].pb(i);
		for(;j<=m&&a[j].first==i;j++){
			if(pos[a[j].second]>pos[a[j].first]){
				g[st[tp]].pb(++cnt);
				g[cnt].pb(st[tp]);
				st[++tp]=cnt;
				pt[cnt].pb(i);
			}
			else{
				g[st[tp]].pb(st[tp-1]);
				g[st[tp-1]].pb(st[tp]);
				tp--;
				pt[st[tp]].pb(i);
			}
		}
		if(++i>n)
			i=1;
	}while(i!=rt);
	for(i=1;i<=cnt;i++){
		sort(all(pt[i]),greater<int>());
		b[i]=i;
	}
	for(i=1;i<=n;i++){
		sort(all(g[i]));
		g[i].erase(unique(all(g[i])),g[i].end());
	}
	mxs[0]=0x7fffffff;
	solve(1,n,1);
	sort(b+1,b+cnt+1,[](int x,int y){return pt[x]<pt[y];});
	for(i=1;i<=cnt;i++)
		printf("%d ",col[b[i]]);
}


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<ext/pb_ds/priority_queue.hpp>
#include<queue>
#include<stack>
#define pb push_back
#define all(a) a.begin(),a.end()
#define pointtype double
#define pointtype_INT 0
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
typedef unsigned uint;
typedef unsigned long long uLL;
const double pi=acos(-1);
template<class T>
void Read(T &x){
	char c;
	bool f(0);
	while(c=getchar(),c!=EOF){
		if(c=='-')
			f=1;
		else if(c>='0'&&c<='9'){
			x=c-'0';
			while(c=getchar(),c>='0'&&c<='9')
				x=x*10+c-'0';
			ungetc(c,stdin);
			if(f)
				x=-x;
			return;
		}
	}
}
struct point{
	pointtype x,y;
	inline point(){
	}
	inline point(pointtype x,pointtype y=0):x(x),y(y){
	}
	inline point operator+(const point &a)const{
		return point(x+a.x,y+a.y);
	}
	inline point operator+=(const point &a){
		return *this=*this+a;
	}
	inline point operator-(const point &a)const{
		return point(x-a.x,y-a.y);
	}
	inline point operator-=(const point &a){
		return *this=*this-a;
	}
	inline bool operator<(const point &b)const{
		if(x==b.x)
			return y<b.y;
		return x<b.x;
	}
	inline bool operator==(const point &b)const{
		return x==b.x&&y==b.y;
	}
	#if pointtype_INT==1
		inline point operator*(const point &a)const{
			return point(1ll*x*a.x-1ll*y*a.y,1ll*x*a.y+1ll*y*a.x);
		}
		inline friend LL cross(const point &a,const point &b){
			return 1ll*a.x*b.y-1ll*a.y*b.x;
		}
		inline friend LL dot(const point &a,const point &b){
			return 1ll*a.x*b.x+1ll*a.y*b.y;
		}
	#else
		inline point operator*(const point &a)const{
			return point(x*a.x-y*a.y,x*a.y+y*a.x);
		}
		inline friend pointtype cross(const point &a,const point &b){
			return a.x*b.y-a.y*b.x;
		}
		inline friend pointtype dot(const point &a,const point &b){
			return a.x*b.x+a.y*b.y;
		}
	#endif
};
template<class T,class T2>
struct hashnode{
	T val;
	T2 v;
	hashnode *next;
};
template<class T,class T2>
inline int& addhash(int u,const T &val,T2 *&ecnt,T2 **adj){
	T2 *p=++ecnt;
	p->val=val;
	p->v=0;
	p->next=adj[u];
	adj[u]=p;
	return p->v;
}
template<class T,class T2,int MOD,int ss>
class hash_table{
	hashnode<T,T2>*adj[MOD],edge[ss+10],*ecnt;
	int sz;
	public:
	inline int Get_val(int x){
		return x%MOD;
	}
	#if pointtype_INT==1
		inline int Get_val(point x){
			return (x.x*998244353ll+x.y)%MOD;
		}
	#endif
	inline hash_table():ecnt(edge),sz(0){
		for(int i=0;i<MOD;i++)
			adj[i]=0;
	}
	inline int size(){
		return sz;
	}
	inline hashnode<T,T2>* hash(const T &x){
		int t=Get_val(x);
		for(hashnode<T,T2> *p=adj[t];p;p=p->next)
			if(p->val==x)
				return p;
		return 0;
	}
	inline int &operator[](const T &x){
		hashnode<T,T2> *p=hash(x);
		if(p)
			return p->v;
		return ++sz,addhash(Get_val(x)%MOD,x,ecnt,adj);
	}
	inline bool count(const T &x){
		return hash(x);
	}
	inline void clear(){
		ecnt=edge;
		int t=MOD>>2<<2,i;
		for(i=0;i<t;i+=4){
			adj[i]=0;
			adj[i+1]=0;
			adj[i+2]=0;
			adj[i+3]=0;
		}
		for(;i<MOD;i++)
			adj[i]=0;
		sz=0;
	}
};
template<class T,int len>
struct polynomial{
	T a[len];
	inline void clear(){
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			a[i]=0;
			a[i+1]=0;
			a[i+2]=0;
			a[i+3]=0;
		}
		for(;i<len;i++)
			a[i]=0;
	}
	inline polynomial operator+(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]+b.a[i];
			c.a[i+1]=a[i+1]+b.a[i+1];
			c.a[i+2]=a[i+2]+b.a[i+2];
			c.a[i+3]=a[i+3]+b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]+b.a[i];
		return c;
	}
	inline polynomial operator+=(const polynomial &b){
		return *this=*this+b;
	}
	inline polynomial operator-(const polynomial &b)const{
		static polynomial c;
		int t=len>>2<<2,i;
		for(i=0;i<t;i+=4){
			c.a[i]=a[i]-b.a[i];
			c.a[i+1]=a[i+1]-b.a[i+1];
			c.a[i+2]=a[i+2]-b.a[i+2];
			c.a[i+3]=a[i+3]-b.a[i+3];
		}
		for(;i<len;i++)
			c.a[i]=a[i]-b.a[i];
		return c;
	}
	inline polynomial operator-=(const polynomial &b){
		return *this=*this-b;
	}
};
//templatef
#define MAXN 100000
map<LL,int>vis;
LL ans,sum;
int n,k,a[MAXN+10];
int main()
{
	Read(n),Read(k);
	int i;
	for(i=1;i<=n;i++)
		Read(a[i]);
	vis[0]++;
	for(i=1;i<=n;i++){
		sum+=a[i];
		LL now=1;
		while(llabs(now)<1e16){
			if(vis.count(sum-now))
				ans+=vis[sum-now];
			now*=k;
			if(k==1||k==-1)
				break;
		}
		vis[sum]++;
	}
	printf("%lld\n",ans);
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <string.h>
#include <fstream>

using namespace std;

#define LL long long
#define N 100010
#define M 400100
#define MP make_pair
#define Pi acos(-1.0)
//#pragma comment(linker,"/STACK:1024000000,1024000000")
#define ls (rt << 1)
#define rs (ls | 1)
#define md ((ll+rr)/2)
#define lson ll, md, ls
#define rson md+1, rr, rs
#define mod 1000000007
#define inf 0x3f3f3f3f
#define sqr(x) ((x)*(x))
#define eps 1e-6
#define uLL unsigned long long
LL powmod(LL a,LL b) {LL res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
#define F(x) ((x)/3+((x)%3 == 1 ? 0 : tb))
#define G(x) ((x)<tb ? (x)*3+1 : ((x) - tb)*3+2)
#define lowbit(x) ((x)&(-x))
#define fi first
#define se second
#define pii pair<int,int>
#define pb push_back
#define MP make_pair
LL gcd(LL x,LL y){
    while(y){
        LL t = x % y;
        x = y;
        y = t;
    }
    return x;
}

template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

int n, m;

vector<int> adj[N];
map<pii, int> vis;
vector<int> vlist[N];
int id[N], pos[N];

int fst[N], vv[M], nxt[M], e;

void init()
{
    e = 0;
    memset(fst, -1, sizeof fst);
}

void add(int u, int v)
{
    if(u > v) return;
   // cout << u << " " << v << endl;
    vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
    vv[e] = u, nxt[e] = fst[v], fst[v] = e++;
}

bool cmp(int a, int b)
{
    for(int i = 0; i < (int)vlist[a].size(); i++)
    {
        int u = vlist[a][i], v = vlist[b][i];
        if(u != v)
            return u < v;
    }
    return 0;
}

int get_nxt(int u, int v)
{
    int i = (int)(lower_bound(adj[u].begin(), adj[u].end(), v) - adj[u].begin());
    if(i == 0) return adj[u].back();
    else return adj[u][i-1];
}

int used[N], fa[N], col[N], ms[N], sz[N], q[N];

int find(int u)
{
    int t = 1; q[0] = u; fa[u] = -1;
    for(int i = 0; i < t; i++)
    {
        u = q[i];
        for(int j = fst[u]; ~j; j = nxt[j])
        {
            int v = vv[j];
            if(!used[v] && v != fa[u]) q[t++] = v, fa[v] = u;
        }
        ms[q[i]] = 0;
        sz[q[i]] = 1;
    }

    for(int i = t - 1; i >= 0; i--)
    {
        ms[q[i]] = max(ms[q[i]],t - sz[q[i]]);
        if(ms[q[i]] * 2 <= t) return q[i];
        sz[fa[q[i]]] += sz[q[i]];
        ms[fa[q[i]]] = max(ms[fa[q[i]]], sz[q[i]]);
    }
    return 0;
}

void solve(int u, int dep)
{

    u = find(u);

    used[u] = 1, col[u] = dep;
    for(int i = fst[u]; ~i; i = nxt[i])
    {
        int v = vv[i];
        if(!used[v]) solve(v, dep + 1);
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    for(int i = 0; i < m; i++)
    {
        int a, b;
        scanf("%d%d",&a,&b);
        a--,b--;
        adj[a].pb(b);
        adj[b].pb(a);
    }

    for(int i = 0; i < n; i++)
    {
        int a = i, b = (i + 1) % n;
        adj[a].pb(b);
        adj[b].pb(a);
        vis[MP(b,a)] = -1;
    }

    for(int i = 0; i < n; i++)
        sort(adj[i].begin(), adj[i].end());

    int region = 0;
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < (int)adj[i].size(); j++)
        {
            int v = adj[i][j];
            while(!vis[MP(i,v)])
            {
                int nu = i, nv = v;
                region++;
                while(true)
                {

                    int nxt = get_nxt(nv, nu);
                    vis[MP(nu, nv)] = region;
                    vlist[region].pb(nu);
                    if(nv == i) break;
                    nu = nv;
                    nv = nxt;
                }
            }
        }
    }

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

    sort(id + 1, id + 1 + region, cmp);

    init();

    for(int i = 1; i <=  region; i++)
        pos[id[i]] = i;

    for(auto i = vis.begin(); i != vis.end(); i++)
    {
        int a = i -> fi.fi, b = i -> fi.se;
        if(vis[MP(b,a)] == -1 || vis[MP(a,b)] == -1) continue;
        add(pos[vis[MP(b,a)]], pos[vis[MP(a,b)]]);
    }
    solve(1, 1);
    for(int i = 1; i <= region; i++)
        printf("%d ",col[i]);
}


/**
 *    author:  [itmo] enot.1.10
 *    created: 23.02.2017 18:39:31
**/
#define __USE_MINGW_ANSI_STDIO 0
#include <bits/stdc++.h>

#define F first
#define S second
#define pb push_back
#define forn(i, n) for(int i = 0 ; (i) < (n) ; ++i)
#define eprintf(...) fprintf(stderr, __VA_ARGS__),fflush(stderr)
#define sz(a) ((int)(a).size())
#define all(a) (a).begin(),a.end()
#define pw(x) (1LL<<(x))

using namespace std;

typedef long long ll;
typedef double dbl;
typedef vector<int> vi;
typedef pair<int, int> pi;

const int inf = 1.01e9;
const dbl eps = 1e-9;

/* --- main part --- */

const int N = 4e5 + 10;

int f[N];
vi e[N];

int n;

unordered_map<ll, int> M;
inline int& used(int x, int y)
{
    return M[x * pw(20) + y];
}

void add(int x, int y)
{
    if (y < x) y += n;
    e[x].pb(y);
}

int id =0;
vi v[N];

void dfs(int x, int y)
{
    //eprintf("dfs %d %d\n", x, y);
    if (used(x, y)) return;
    v[id].pb(x);
    used(x, y) = 1;
    y %= n;
    if (x < y) x += n;
    int pos = lower_bound(all(e[y]), x) - e[y].begin();
    assert(pos >= 0);
    pos--;
    dfs(y, e[y][pos]);
}

int p[N];

inline bool comp(int x, int y)
{
    return v[x] < v[y];
}

unordered_map<ll, vi> HA;

void ADD(int x, int y, int who)
{
    if (x > y) swap(x, y);
    HA[x * pw(20) + y].pb(who);
}

vi t[N];

int cnt[N];
int dead[N];

void dfs1(int x, int xx)
{
    cnt[x] = 1;
    for (int y : t[x])
    {
        if (!dead[y] && y != xx)
        {
            dfs1(y, x);
            cnt[x] += cnt[y];
        }
    }
}

int OK(int x, int all)
{
    if (2 * x <= all + 1) return 1;
    return 0;
}

int dfs2(int x, int xx, int all)
{
    int ok = OK(all - cnt[x], all);
    for (int y : t[x])
    {
        if (!dead[y] && y != xx) ok &= OK(cnt[y], all);
    }
    if (ok) return x;
    for (int y : t[x])
    {
        if (!dead[y] && y != xx)
        {
            int r = dfs2(y, x, all);
            if (r != -1) return r;
        }
    }
    return -1;
}

int res[N];

void go(int x, int col = 1)
{
    dfs1(x, -1);
    x = dfs2(x, -1, cnt[x]);

    res[x] = col;
    dead[x] = 1;

    for (int y : t[x]) if (!dead[y]) go(y, col + 1);
}

int main()
{
    #ifdef home
        assert(freopen("1.in", "r", stdin));
        assert(freopen("1.out", "w", stdout));
    #endif
    int m;
    scanf("%d%d", &n, &m);
    forn(i, m)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        --x, --y;
        add(x, y);
        add(y, x);
    }
    forn(i, n)
    {
        int x = i;
        int y = (i + 1) % n;
        add(x, y);
        //add(y, x);
    }

    //build
    forn(i, n)
    {
        sort(all(e[i]));
        //eprintf("i = %d, e = ", i);
        //for (int y : e[i]) eprintf("%d ", y);
        //eprintf("\n");
    }

    forn(x, n) for (int y : e[x])
    {
        //eprintf("x = %d, y = %d\n", x, y);
        if (used(x, y)) continue;

        dfs(x, y);
        if (sz(v[id]) == 1)
        {
            //eprintf("!!\n");
            v[id].clear();
            continue;
        }

        forn(i, sz(v[id]))
        {
            int xx = v[id][i];
            int yy = v[id][(i + 1) % sz(v[id])];
            ADD(xx, yy, id);
        }

        sort(all(v[id]));
        reverse(all(v[id]));

        id++;

    }

    forn(i, id) p[i] = i;
    sort(p, p + id, comp);

    /*forn(ii, id)
    {
        int i = p[ii];
        eprintf("new group %d\n", ii);
        for (int z : v[i]) eprintf("%d ", z);
        eprintf("\n");
    }  */

    for (auto it : HA)
    {
        if (sz(it.S) == 2)
        {
            int x = it.S[0];
            int y = it.S[1];
            t[x].pb(y);
            t[y].pb(x);
        }
    }

    go(0);

    forn(ii, id)
    {
        int i = p[ii];
        printf("%d%c", res[i], " \n"[ii + 1 == id]);
    }

    #ifdef home
        eprintf("time = %d ms\n", (int)(clock() * 1000. / CLOCKS_PER_SEC));
    #endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

vector<int> graph[100005];
map<pair<int, int>, int> edge_idx;
int parent[300005];
int gidx[300005];
set<int, greater<>> elem[300005];

int idx(int a, int b)
{
	return edge_idx.insert({ {a, b}, (int)edge_idx.size() + 1 }).first->second;
}

int getparent(int t)
{
	if (parent[t] == 0) parent[t] = t;
	return t == parent[t] ? t : parent[t] = getparent(parent[t]);
}

void merge(int a, int b)
{
	parent[getparent(a)] = getparent(b);
}

map<set<int, greater<>>, int> dual_idx;
vector<int> dual_graph[100005];
pair<int, int> diag[100005];
int ans[100005];
bool block[100005];
int f1, f2;

void dfs(int t, int p, int len, int target = -1)
{
	if (len == target)
	{
		f1 = t;
		return;
	}

	if (f2 < len)
	{
		f2 = len;
		f1 = t;
	}

	for (int nxt : dual_graph[t])
	{
		if (p == nxt || block[nxt]) continue;
		dfs(nxt, t, len + 1, target);
	}
}

void recur(int t, int col)
{
	f2 = -1;

	dfs(t, -1, 0);
	f2 = 0;
	dfs(f1, -1, 0);
	dfs(f1, -1, 0, f2 / 2);

	ans[f1] = col;
	block[f1] = true;
	for (int nxt : dual_graph[f1])
	{
		if (block[nxt]) continue;
		recur(nxt, col + 1);
	}
}

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i < n; i++)
	{
		graph[i].push_back(i + 1);
	}
	graph[n].push_back(1);
	for (int i = 0; i < m; i++)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		//a = 1; b = i + 3;
		graph[a].push_back(b);
		graph[b].push_back(a);

		diag[i] = { a, b };
	}

	for (int i = 1; i <= n; i++) sort(graph[i].begin(), graph[i].end());

	for (int i = 1; i <= n; i++)
	{
		for (int j : graph[i])
		{
			int k = (lower_bound(graph[j].begin(), graph[j].end(), i) - graph[j].begin() + graph[j].size() - 1) % graph[j].size();
			merge(idx(i, j), idx(j, graph[j][k]));
		}
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j : graph[i])
		{
			int k = idx(i, j);
			elem[getparent(k)].insert(i);
			elem[getparent(k)].insert(j);
		}
	}

	for (int i = 1; i <= edge_idx.size(); i++)
	{
		if (elem[i].empty()) continue;
		dual_idx.emplace(elem[i], 0);
	}

	{
		int f = 0;
		for (auto &&e : dual_idx)
		{
			e.second = f++;
		}
	}

	for (int i = 1; i <= edge_idx.size(); i++)
	{
		if (elem[i].empty()) continue;
		gidx[i] = dual_idx[elem[i]];
	}

	for (int i = 0; i < m; i++)
	{
		int a = idx(diag[i].first, diag[i].second);
		int b = idx(diag[i].second, diag[i].first);

		dual_graph[gidx[getparent(a)]].push_back(gidx[getparent(b)]);
		dual_graph[gidx[getparent(b)]].push_back(gidx[getparent(a)]);
	}

	recur(0, 1);
	for (int i = 0; i < dual_idx.size(); i++)
	{
		printf("%d ", ans[i]);
	}
	printf("\n");
}