#define NAAN_TIKE_PLATYPUS
#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <cstring>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <unordered_set>
#include <unordered_map>
#include <array>
#include <cassert>
#include <bitset>
#include <cstdint>
using namespace std;
using LL = long long;

#include <vector>
using namespace std;
using LL = long long;

namespace scc_space {
	void dfs(int v_, vector<bool>& used_, vector<int>G_[], vector<int>& vs_) {
		used_[v_] = true;
		for (int nxt : G_[v_]) {
			if (!used_[nxt])dfs(nxt, used_, G_, vs_);
		}
		vs_.push_back(v_);
	}

	void rdfs(int v_, int k_, vector<bool>& used_, vector<vector<int>>& rG_, vector<int>& top) {
		used_[v_] = true;
		top[v_] = k_;
		for (int nxt : rG_[v_]) {
			if (!used_[nxt])rdfs(nxt, k_, used_, rG_, top);
		}
	}
}

//頂点数n_のグラフG_の強連結成分分解をする
//topに強連結成分のトポロジカル順序が格納される
//(top[i]==top[j]のとき、iとjは強連結である。)
//戻り値:強連結成分の個数
int scc(vector<int>G_[], int n_, vector<int>& top) {
	using namespace scc_space;
	top.resize(n_);
	vector<vector<int>>rG_(n_);
	for (int i = 0; i < n_; ++i) {
		for (int to : G_[i]) {
			rG_[to].push_back(i);
		}
	}
	vector<bool>used(n_, false);
	vector<int>vs;
	for (int v = 0; v < n_; ++v) {
		if (!used[v])dfs(v, used, G_, vs);
	}
	fill(used.begin(), used.end(), false);
	int k = 0;
	for (int i = vs.size() - 1; i >= 0; --i) {
		if (!used[vs[i]])rdfs(vs[i], k++, used, rG_, top);
	}
	return k;
}

int N, M;
vector<int>G[1234];

int main() {
	cin >> N >> M;
	for (int i = 0; i < M; ++i) {
		int a, b;
		cin >> a >> b;
		--a; --b;
		G[a].push_back(b);
	}
	vector<int>top;
	scc(G, N, top);
	map<int, vector<int>>mp;
	for (int i = 0; i < N; ++i) {
		mp[top[i]].push_back(i);
	}
	for (auto& p : mp) {
		sort(p.second.begin(), p.second.end());
	}
	for (int i = 0; i < N; ++i) {
		for (int x = 0; x < mp[top[i]].size(); ++x) {
			cout << mp[top[i]][x] + 1 << " \n"[x + 1 == mp[top[i]].size()];
		}
	}
	return 0;
}
