#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <fstream>
#include <list>
using namespace std;
ifstream fin("ctc.in");
ofstream fout("ctc.out");
struct Edge
{
int source;
int destination;
int cost;
Edge(int source = 0,int destination = 0,int cost = 0):
source(source),
destination(destination),
cost(cost) { }
};
class Graph{
private:
//private variables
int vertices, edges;
bool oriented, weighted;
vector<vector<Edge>> adjacency_list;
//To compute:
vector<int> distances;
vector<list<int>> biconnected_components;
vector<vector<int>> strongly_connected_components;
vector<int> topological;
vector<pair<int,int>> bridges;
//private functions
void BFS(int starting_vertex);
void DFS(int vertex, vector<int>& visited);
void BCCTJ(); //Tarjan Algorithm
void BCCKJ(); //Kosaraju Algorithm
void SCC(int vertex, stack<int>& vertices_stack, vector<int>& discovery_time, vector<int>& lowest_reachable, vector<bool>& has_component,int& timer);
void CCN();
void TOPOLOGICAL_SORT(int vertex, vector<int>& visited);
vector<int> BFSMD(int starting_vertex);
public:
Graph(int vertices = 0,int edges = 0,bool oriented = false,bool weighted = false);
void infoarena_graph();
void show_my_graph();
void solve_distances(int starting_vertex);
void solve_connected_components();
void solve_biconnected();
void solve_strongly_connected();
void solve_topological();
void solve_critical_connections();
void solve_starting_ending_distance(int starting_vertex,int ending_vertex);
};
void printv(vector<int> xs){
for(int i : xs) cout<<i<<' ';
cout<<'\n';
}
int main()
{
int n, m;
fin>>n>>m;
Graph g(n,m,true);
g.infoarena_graph();
g.solve_strongly_connected();
}
Graph::Graph(int vertices, int edges, bool oriented, bool weighted) :
vertices(vertices),
edges(edges),
oriented(oriented),
weighted(weighted)
{
adjacency_list.resize(vertices + 1);
}
void Graph::infoarena_graph() {
int x,y;
int c = 0;
for(int i = 1;i<=edges;i++)
{
fin>>x>>y;
if(weighted)
fin>>c;
adjacency_list[x].push_back(Edge(x,y,c));
if(!oriented)
adjacency_list[y].push_back(Edge(y,x,c));
}
}
void Graph::show_my_graph() {
for(int i = 1;i<=vertices;i++){
cout<<i<<"=>";
for(auto path : adjacency_list[i])
cout<<path.destination<<' ';
cout<<'\n';
}
}
void Graph::BFS(int starting_vertex)
{
distances.resize(vertices+1,-1);
queue<int> que;
que.push(starting_vertex);
distances[starting_vertex] = 0;
while(!que.empty()){
int vert = que.front();
que.pop();
for(auto path : adjacency_list[vert])
if(distances[path.destination] == -1){
que.push(path.destination);
distances[path.destination] = distances[vert] + 1;
}
}
}
void Graph::DFS(int vertex, vector<int>& visited)
{
visited[vertex] = 1;
for(auto path : adjacency_list[vertex])
if(!visited[path.destination])
DFS(path.destination,visited);
}
void Graph::SCC(int vertex,stack<int>& vertices_stack, vector<int>& discovery_time,vector<int>& lowest_reachable, vector<bool>& has_component, int& timer)
{
discovery_time[vertex] = lowest_reachable[vertex] = ++timer;
vertices_stack.push(vertex);
for(auto path : adjacency_list[vertex])
{
if(discovery_time[path.destination]==-1)
{
SCC(path.destination,vertices_stack,discovery_time,lowest_reachable,has_component,timer);
lowest_reachable[vertex] = min(lowest_reachable[vertex],lowest_reachable[path.destination]);
}
else if (!has_component[path.destination])
lowest_reachable[vertex] = min(lowest_reachable[vertex],discovery_time[path.destination]);
}
if(lowest_reachable[vertex] == discovery_time[vertex])
{
vector<int> component;
int temp;
do{
temp = vertices_stack.top();
vertices_stack.pop();
has_component[temp] = true;
component.push_back(temp);
}while(temp!=vertex);
strongly_connected_components.push_back(component);
}
}
void Graph::TOPOLOGICAL_SORT(int vertex, vector<int>& visited){
visited[vertex] = 1;
for(auto path : adjacency_list[vertex])
if(!visited[path.destination])
TOPOLOGICAL_SORT(path.destination,visited);
topological.push_back(vertex);
}
void Graph::solve_distances(int starting_vertex)
{
BFS(starting_vertex);
for(int i = 1;i<vertices+1;i++)
fout<<distances[i]<<' ';
}
void Graph::solve_connected_components()
{
vector<int> visited(vertices+1,0);
int cnt = 0;
for(int i = 1;i<=vertices;i++)
if(!visited[i])
DFS(i,visited),cnt++;
fout<<cnt;
}
void Graph::solve_strongly_connected()
{
stack<int> vertices_stack;
vector<int> discovery_time(vertices+1,-1);
vector<int> lowest_reachable(vertices+1,-1);
vector<bool> has_component(vertices+1,false);
int timer = 0;
for(int i = 1;i<vertices+1;i++)
if(discovery_time[i] == -1)
SCC(i,vertices_stack,discovery_time,lowest_reachable,has_component,timer);
fout<<strongly_connected_components.size()<<'\n';
for(auto component : strongly_connected_components){
for(auto i : component) fout<<i<<' ';
fout<<'\n';
}
}
void Graph::solve_topological()
{
vector<int> visited(vertices+1,0);
for(int i = 1;i<=vertices;i++)
if(!visited[i])
TOPOLOGICAL_SORT(i,visited);
for(int i = topological.size()-1;i>=0;i--)
fout<<topological[i]<<' ';
}