#include <bits/stdc++.h>
using namespace std;
/*
/// FISIERE BFS
ifstream in("bfs.in");
ofstream out("bfs.out");
/// FISIERE DFS
ifstream in("dfs.in");
ofstream out("dfs.out");
/// FISIERE BICONEX
ifstream in("biconex.in");
ofstream out("biconex.out");
*/
/// FISIERE CTC
ifstream in("ctc.in");
ofstream out("ctc.out");
class Graf
{
int nr_N, nr_M, S, V[100001];
vector<int> adiac[100001];
vector<vector<int>> GT, G; /// GT = GRAF TRANSPUS(PENTRU CTC)
vector<int> nma; ///NIVEL MINIM ACCESIBIL
vector<int> nivel;
public:
/// Constructori
Graf() : nr_N(0), nr_M(0) {}
Graf(int N, int M) : nr_N(N), nr_M(M) {}
void citire_or();
void citire_neor();
void citire_or_CTC();
void BFS();
void DFS(int, vector<int>&);
void conexe();
void nma_nivel(int, int, vector<vector<int>>&, vector<int>&, vector<int>&, stack<int>&, int&, vector<int>&);
void Biconex();
void CTC();
void DFS_G_CTC(int, vector<int>&, vector<bool>&);
void DFS_GT_CTC(int, vector<bool>&, vector<vector<int>>&, int&);
};
void Graf::citire_or() /// CITIRE GRAF ORIENTAT
{
in >> nr_N >> nr_M >> S;
for (int i = 0; i < nr_M; i++)
{
int x, y;
in >> x >> y;
adiac[x].push_back(y);
}
}
void Graf::citire_or_CTC() /// CITIRE GRAF ORIENTAT PENTRU CTC
{
in >> nr_N >> nr_M;
G = GT = vector<vector<int>>(nr_N + 1);
for (int i = 0; i < nr_M; i++)
{
int x, y;
in >> x >> y;
G[x].push_back(y);
GT[y].push_back(x);
}
}
void Graf::citire_neor() /// CITIRE GRAF NEORIENTAT
{
in >> nr_N >> nr_M;
for (int i = 0; i < nr_M; i++)
{
int x, y;
in >> x >> y;
adiac[x].push_back(y);
adiac[y].push_back(x);
}
}
void Graf::BFS() /// BFS
{
queue <int> coada;
int nod;
int vizitat[100001] = {};
vizitat[S] = 1;
coada.push(S);
int cost[100001] = {};
cost[S] = 0;///Costul la nodul de start este 0
while(coada.size() > 0) ///Cat timp inca mai am noduri in graf
{
nod = coada.front();
for(int j = 0; j < adiac[nod].size(); j++)
{
if(vizitat[adiac[nod][j]] == 0)
{
coada.push(adiac[nod][j]);
cost[adiac[nod][j]] = cost[nod] + 1;
vizitat[adiac[nod][j]]++;
}
}
coada.pop();
}
for(int i = 1; i <= nr_N; i++)
{
if(vizitat[i] == 0) out << "-1 ";
else out << cost[i] << " ";
}
}
void Graf::DFS(int S, vector<int>& vizitat) /// DFS
{
vizitat[S] = 1;
for(int i = 0; i < adiac[S].size(); i++)
{
if (vizitat[adiac[S][i]] ==0)
{
///cout << adiac[S][i] << " ";
DFS(adiac[S][i], vizitat);
}
}
}
void Graf::conexe() /// NUMARARE COMPONENTE CONEXE PENTRU DFS
{
vector<int> vizitat;
int nr=0, i;
for(i = 0; i <= nr_N; i++)
vizitat.push_back(0);
for(i = 1; i <= nr_N; i++)
{
if (vizitat[i] == 0)
{
DFS(i,vizitat);
nr++;
}
}
out << nr;
}
void Graf::nma_nivel(int k, int tata, vector<vector<int>>& componente_bi, vector<int>& nma, vector<int>& nivel, stack<int>& stiva, int& nr, vector<int>& V) /// BICONEX_DFS
{
V[k] = 1;
stiva.push(k);
nivel[k] = nivel[tata] + 1;
nma[k] = nivel[k];
for(int i = 0; i < adiac[k].size(); i++)
{
int x = adiac[k][i];
///cout << "test ";
if(x != tata)
{
if(V[x] == 1)
{
///cout << k << " " << adiac[k][i] << " | ";
if(nma[k] > nivel[x])
nma[k] = nma[x];
}
else
{
nma_nivel(adiac[k][i], k, componente_bi, nma, nivel, stiva, nr, V);
if(nma[k] > nma[x])
{
nma[k] = nma[adiac[k][i]];
}
if(nivel[k] <= nma[x])
{
///cout << k << " " << adiac[k][i] << " | ";
while (stiva.top() != x)
{
componente_bi[nr].push_back(stiva.top());
stiva.pop();
}
componente_bi[nr].push_back(x);
stiva.pop();
componente_bi[nr].push_back(k);
nr++;
}
}
}
}
}
void Graf::Biconex() /// BICONEX
{
vector<vector<int>> componente_bi;
componente_bi.resize(nr_N + 1);
vector<int> nma(nr_N + 1), nivel(nr_N + 1), V(nr_N + 1);
int nr = 0;
stack<int> stiva;
///cout << "test";
nma_nivel(1, 0, componente_bi, nma, nivel, stiva, nr, V);
///cout << "TEST";
out << nr << '\n';
for(int i = 0; i < nr; i++)
{
for(int j = 0; j < componente_bi[i].size(); j++)
{
out << componente_bi[i][j] << " ";
}
out << '\n';
}
}
void Graf::DFS_G_CTC(int k, vector<int>& stiva_CTC, vector<bool>& V_CTC)
{
V_CTC[k] = true;
for(auto x : G[k])
if(!V_CTC[x])
DFS_G_CTC(x, stiva_CTC, V_CTC);
stiva_CTC.push_back(k);
}
void Graf::DFS_GT_CTC(int k, vector<bool>& V_CTC, vector<vector<int>>& componente_tc, int& contor)
{
V_CTC[k] = true;
for(auto x : GT[k])
if(!V_CTC[x])
DFS_GT_CTC(x, V_CTC, componente_tc, contor);
componente_tc[contor].push_back(k);
}
void Graf::CTC()
{
/// adiac este G
vector<vector<int>> componente_tc;
componente_tc.resize(nr_N + 1);
vector<int> stiva_CTC;
vector<bool> V_CTC;
int nr = 0;
V_CTC = vector<bool> (nr_N + 1, false);
for(int i = 1; i <= nr_N; i++)
{
if(!V_CTC[i])
DFS_G_CTC(i, stiva_CTC, V_CTC);
}
V_CTC = vector<bool> (nr_N + 1, false);
for(vector<int>::reverse_iterator it = stiva_CTC.rbegin() ; it != stiva_CTC.rend() ; it ++)
if(!V_CTC[*it])
{
nr++;
DFS_GT_CTC(*it, V_CTC, componente_tc, nr);
}
out << nr << '\n';
for(int i = 0; i <= nr_N; i++)
{
if(componente_tc[i].size() >= 1)
{
for(int j = 0; j <componente_tc[i].size(); j++)
{
out << componente_tc[i][j] << " ";
}
out << '\n';
}
}
}
int main()
{
Graf G;
/*
///BFS
G.citire_or();
G.BFS();
///DFS
G.citire_neor();
G.conexe();
///Biconex
G.citire_neor();
G.Biconex();
*/
///CTC
G.citire_or_CTC();
G.CTC();
return 0;
}