#include <bits/stdc++.h>
#include <iostream>
#include <fstream>
using namespace std;
ifstream f("ctc.in");
ofstream g("ctc.out");
class graf
{
private:
int n;
vector<vector< int > > vecini;
int grad_int[100001];
int grad_ext[100001];
public:
graf(int n);
void citire_graf_orientat(int m);
void citire_graf_neorientat(int m);
void BFS(int start);
void DFS(int start, bool vizitat[]);
int nr_comp_conexe();
void sortare_topologica();
void ctc();
void DFS2(int start, int vizitat[], stack <int>& stiva);
void DFS_Transpus(int start, int vizitat[],vector <vector<int> >& vecini_transpus,vector <vector<int> >& rezultat, int &Nr_comp_tare_conexe);
void Componente_Biconexe();
void DFS3(int start,int tata[], bool vizitat[], stack <pair <int,int> > &stiva_muchii, int nivel[],int nivel_minim[],vector<vector< int > >&solutie,int nivel_curent);
void Muchii_Critice();
void DFS_MC(int start,int tata[], bool vizitat[], stack <pair <int,int> > &stiva_muchii, int nivel[],int nivel_minim[],vector<pair <int,int> >&solutie,int nivel_curent);
};
graf :: graf(int N)
{
n=N;
vecini.resize(n+1);
for(int i=1;i<=n;i++){
grad_int[i]=0;
grad_ext[i]=0;
}
}
void graf :: citire_graf_orientat(int M)
{
int a,b;
for(int i=1;i<=M;i++){
f>>a>>b;
grad_ext[a]++;
grad_int[b]++;
vecini[a].push_back(b);
}
}
void graf :: citire_graf_neorientat(int m)
{
int a,b;
for(int i=1;i<=m;i++){
f>>a>>b;
grad_ext[a]++;
grad_ext[b]++;
grad_int[a]++;
grad_int[b]++;
vecini[a].push_back(b);
vecini[b].push_back(a);
}
}
void graf :: BFS(int start)
{
queue <int> coada;
int distanta[n+1];
for(int i=1;i<=n;i++){
distanta[i]=-1;
}
coada.push(start);
distanta[start]=0;
while(coada.empty()==0){
for(int i=0;i<int(vecini[coada.front()].size());i++){
if(distanta[vecini[coada.front()][i]]==-1){
coada.push(vecini[coada.front()][i]);
distanta[vecini[coada.front()][i]]=distanta[coada.front()]+1;
}
}
coada.pop();
}
for(int i=1;i<=n;i++){
g<<distanta[i]<<" ";
}
}
int graf :: nr_comp_conexe()
{
bool vizitat[n+1];
int Nr=0;
for(int i=1;i<=n;i++){
vizitat[i]=0;
}
for(int i=1;i<=n;i++){
if(vizitat[i]==0){
Nr++;
DFS(i, vizitat);
}
}
return Nr;
}
void graf :: DFS(int start, bool vizitat[])
{
vizitat[start]=1;
for(int i=0;i<int(vecini[start].size());i++){
if(vizitat[vecini[start][i]]==0){
vizitat[vecini[start][i]]=1;
DFS(vecini[start][i],vizitat);
}
}
}
void graf :: sortare_topologica()
{
vector<int> rezolvare;
bool vizitat[n+1];
for(int i=1;i<=n;i++){
vizitat[i]=0;
}
while(rezolvare.size()<n){
for(int i=1;i<=n && rezolvare.size()<n;i++){
if(grad_int[i]==0 && vizitat[i]==0){
rezolvare.push_back(i);
vizitat[i]=1;
for(int j=0;j<int(vecini[i].size());j++){
grad_int[vecini[i][j]]--;
}
}
}
}
for(int i=0;i<n;i++){
g<<rezolvare[i]<<" ";
}
}
void graf :: DFS2(int start, int vizitat[], stack <int>& stiva)
{
vizitat[start]=1;
for(int i=0;i<int(vecini[start].size());i++){
if(vizitat[vecini[start][i]]==0){
vizitat[vecini[start][i]]=1;
DFS2(vecini[start][i],vizitat,stiva);
}
}
stiva.push(start);
}
void graf :: DFS_Transpus(int start, int vizitat[],vector <vector<int> >& vecini_transpus,vector <vector<int> >& rezultat, int &Nr_comp_tare_conexe)
{
vizitat[start]=2;
rezultat[Nr_comp_tare_conexe].resize(rezultat[Nr_comp_tare_conexe].size());
rezultat[Nr_comp_tare_conexe].push_back(start);
for(int i=0;i<int(vecini_transpus[start].size());i++){
if(vizitat[vecini_transpus[start][i]]==1){
DFS_Transpus(vecini_transpus[start][i],vizitat,vecini_transpus,rezultat, Nr_comp_tare_conexe);
}
}
}
void graf :: ctc()
{
vector <vector<int> > rezultat;
stack <int> stiva;
int vizitat[n+1];
int Nr_comp_tare_conexe=0;
for(int i=1;i<=n;i++){
vizitat[i]=0;
}
vector <vector<int> > vecini_transpus;
vecini_transpus.resize(n+1);
rezultat.resize(n+1);
for(int i=1;i<=n;i++){
for(int j=0;j<vecini[i].size();j++){
vecini_transpus[vecini[i][j]].push_back(i);
}
}
for(int i=1;i<=n;i++){
if(vizitat[i]==0){
DFS2(i,vizitat,stiva);
}
}
while(stiva.size()>0){
if(vizitat[stiva.top()]==1){
Nr_comp_tare_conexe++;
DFS_Transpus(stiva.top(),vizitat,vecini_transpus,rezultat, Nr_comp_tare_conexe);
}
stiva.pop();
}
g<<Nr_comp_tare_conexe<<'\n';
for(int i=1;i<=Nr_comp_tare_conexe;i++){
for(int j=0;j<int(rezultat[i].size());j++){
g<<rezultat[i][j]<<" ";
}
g<<'\n';
}
}
void graf :: Componente_Biconexe()
{
bool vizitat[n+1];
int nivel[n+1];
int nivel_minim[n+1];
stack <pair <int,int> > stiva_muchii;
int tata[n+1];
for(int i=1;i<=n;i++){
nivel[i]=-1;
}
for(int i=1;i<=n;i++){
vizitat[i]=0;
}
for(int i=1;i<=n;i++){
tata[i]=0;
}
vector<vector< int > >solutie;
DFS3(1,tata, vizitat,stiva_muchii, nivel,nivel_minim,solutie,0);
while(stiva_muchii.size()>0){///aici o sa ramana muchiile critice + cele care leaga noduri "cu un singur vecin"
vector <int> temporar_noduri;
temporar_noduri.push_back(stiva_muchii.top().first);
temporar_noduri.push_back(stiva_muchii.top().second);
solutie.push_back(temporar_noduri);
stiva_muchii.pop();
}
g<<solutie.size()<<'\n';
for(int i=0;i<solutie.size();i++){
for(int j=0;j<solutie[i].size();j++){
g<<solutie[i][j]<<" ";
}
g<<'\n';
}
}
void graf :: DFS3(int start,int tata[], bool vizitat[], stack <pair <int,int> > &stiva_muchii, int nivel[],int nivel_minim[],vector<vector< int > >&solutie,int nivel_curent)
{
vizitat[start]=1;
nivel[start]=nivel_curent;
nivel_minim[start]=nivel_curent;
if(vecini[start].size()==1){///aici o sa ramana muchii critice care leaga un nod "cu un singur vecin" de vecinul sau, deci e muchie critica
vector<int> temporar_noduri;
temporar_noduri.push_back(stiva_muchii.top().first);
temporar_noduri.push_back(stiva_muchii.top().second);
solutie.push_back(temporar_noduri);
stiva_muchii.pop();
}
else{
for(int i=0;i<int(vecini[start].size());i++){
if(vizitat[vecini[start][i]]==1 && nivel[vecini[start][i]]<nivel[start] && vecini[start][i] != tata[start]){
stiva_muchii.push(make_pair(start,vecini[start][i]));
nivel_minim[start]=min(nivel_minim[start],nivel[vecini[start][i]]+1);
tata[start]=vecini[start][i];
}
else
if(vizitat[vecini[start][i]]==0){
tata[vecini[start][i]]=start;
stiva_muchii.push(make_pair(start,vecini[start][i]));
DFS3(vecini[start][i],tata,vizitat,stiva_muchii,nivel,nivel_minim,solutie,nivel_curent+1);
if(nivel_minim[vecini[start][i]] <= nivel[start]){
vector<int> temporar_muchii[2];
vector<int> temporar_noduri;
do{
temporar_muchii[0].push_back(stiva_muchii.top().first);
temporar_muchii[1].push_back(stiva_muchii.top().second);
stiva_muchii.pop();
}while(stiva_muchii.top().first!=tata[vecini[start][i]]);
temporar_muchii[0].push_back(stiva_muchii.top().first);
temporar_muchii[1].push_back(stiva_muchii.top().second);
stiva_muchii.pop();
for(int j=0;j<temporar_muchii[1].size();j++){
temporar_noduri.push_back(temporar_muchii[0][j]);
}
solutie.push_back(temporar_noduri);
}
}
}
}
}
void graf :: Muchii_Critice()
{
bool vizitat[n+1];
int nivel[n+1];
int nivel_minim[n+1];
stack <pair <int,int> > stiva_muchii;
int tata[n+1];
for(int i=1;i<=n;i++){
nivel[i]=-1;
}
for(int i=1;i<=n;i++){
vizitat[i]=0;
}
for(int i=1;i<=n;i++){
tata[i]=0;
}
vector<pair <int,int> >solutie;
DFS_MC(1,tata, vizitat,stiva_muchii, nivel,nivel_minim,solutie,0);
while(stiva_muchii.size()>0){///aici o sa ramana muchiile critice + cele care leaga noduri "cu un singur vecin"
solutie.push_back(make_pair(stiva_muchii.top().first,stiva_muchii.top().second));
stiva_muchii.pop();
}
g<<"[";
for(int i=0;i<solutie.size();i++){
g<<"["<<solutie[i].first<<","<<solutie[i].second<<"]";
if(i!=solutie.size()-1){
g<<",";
}
else
g<<"]";
}
}
void graf :: DFS_MC(int start,int tata[], bool vizitat[], stack <pair <int,int> > &stiva_muchii, int nivel[],int nivel_minim[],vector<pair <int,int> >&solutie,int nivel_curent)
{
vizitat[start]=1;
nivel[start]=nivel_curent;
nivel_minim[start]=nivel_curent;
if(vecini[start].size()==1){///aici o sa ramana muchii critice care leaga un nod "cu un singur vecin" de vecinul sau, deci e muchie critica
solutie.push_back(make_pair(stiva_muchii.top().first,stiva_muchii.top().second));
stiva_muchii.pop();
}
else{
for(int i=0;i<int(vecini[start].size());i++){
if(vizitat[vecini[start][i]]==1 && nivel[vecini[start][i]]<nivel[start] && vecini[start][i] != tata[start]){
stiva_muchii.push(make_pair(start,vecini[start][i]));
nivel_minim[start]=min(nivel_minim[start],nivel[vecini[start][i]]+1);
tata[start]=vecini[start][i];
}
else
if(vizitat[vecini[start][i]]==0){
tata[vecini[start][i]]=start;
stiva_muchii.push(make_pair(start,vecini[start][i]));
DFS_MC(vecini[start][i],tata,vizitat,stiva_muchii,nivel,nivel_minim,solutie,nivel_curent+1);
if(nivel_minim[vecini[start][i]] <= nivel[start]){
do{
stiva_muchii.pop();
}while(stiva_muchii.top().first!=tata[vecini[start][i]]);
stiva_muchii.pop();
}
}
}
}
}
bool Havel_Hakimi(vector<int>grade)
{
sort(grade.begin(),grade.end());
if(grade[grade.size()-1]>grade.size()-1){
return false;
}
while(grade[0]>=0){
int cel_cel_mai_mare_grad=grade[grade.size()-1];
grade.pop_back();
if(cel_cel_mai_mare_grad>grade.size()){
return false;
}
for(int i=grade.size()-1;i>=0;i--){
cel_cel_mai_mare_grad--;
grade[i]--;
if(cel_cel_mai_mare_grad==0){
break;
}
}
if(cel_cel_mai_mare_grad!=0){
return false;
}
sort(grade.begin(),grade.end());
while(*grade.begin()==0 && grade.size()!=0){
grade.erase(grade.begin());
}
if(grade.size()==0 || grade[0]==0){
return true;
}
}
return false;
}
int n,m,S;
int main ()
{
f>>n>>m;
graf G(n);
///Rezolvare problema BFS
//f>>S;
//G.citire_graf_orientat(m);
//G.BFS(S);
///Rezolvare problema DFS - Componente Conexe
//G.citire_graf_neorientat(m);
//g<<G.nr_comp_conexe();
///Rezolvare Sortare Topologica
/*
G.citire_graf_orientat(m);
G.sortare_topologica();
*/
///Rezolvare Componente Tare Conexe
G.citire_graf_orientat(m);
G.ctc();
///Rezolvare Componente Biconexe
/*
G.citire_graf_neorientat(m);
G.Componente_Biconexe();
*/
///Rezolvare Muchii Critice
/*
G.citire_graf_neorientat(m);
G.Muchii_Critice();
*/
///Rezolvare Havel Hakimi
/*
vector <int> grade;
cin>>n;
for(int i=0;i<n;i++){
int x;
cin>>x;
grade.push_back(x);
}
cout<<Havel_Hakimi(grade);
*/
return 0;
}