import std;
import core.bitop;

ulong MAX = 100_100, MOD = 1_000_000_007, INF = 1_000_000_000_000;
alias sread = () => readln.chomp();
alias lread(T = long) = () => readln.chomp.to!(T);
alias aryread(T = long) = () => readln.split.to!(T[]);
alias Pair = Tuple!(long, "B", long, "W");
alias PQueue(T, alias less = "a>b") = BinaryHeap!(Array!T, less);

class UnionFind
{
    long n;
    long[] par;

    this(long init)
    {
        n = init;
        par = iota(n).array();
    }

    long root(long x)
    {
        if (par[x] == x)
            return x;
        else
            return par[x] = root(par[x]);
    }

    void unit(long x, long y)
    {
        if (root(x) != root(y))
            par[root(x)] = root(y);
    }

    bool same(long x, long y)
    {
        return (root(x) == root(y));
    }
}

void main()
{
    long n, m;
    scan(n, m);

    auto uf = new UnionFind(n);
    foreach (i; iota(m))
    {
        long a, b;
        scan(a, b);
        uf.unit(a - 1, b - 1);
    }
    iota(n).map!(x => uf.root(x)).array.sort.array.group.assocArray.reduce!(max).writeln();
}

void scan(TList...)(ref TList Args)
{
    auto line = readln.split();
    foreach (i, T; TList)
    {
        T val = line[i].to!(T);
        Args[i] = val;
    }
}
