#include <fstream>
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
ifstream fin("ctc.in");
ofstream fout("ctc.out");
struct muchie {
int destinatie, cost, capacitate;
muchie(int destinatie, int cost, int capacitate) : destinatie(destinatie), cost(cost), capacitate(capacitate) {}
};
class Graf {
private:
int nrNoduri, nrMuchii;
bool eOrientat, arePonderi, areCapacitati;
vector<vector<muchie>> listaDeAdiacenta;
public:
Graf(int nrNoduri, int nrMuchii, bool eOrientat, bool arePonderi, bool areCapacitati);
void citire();
void componenteTareConexe();
private:
void DFSsortareTopologica(int nodPlecare, stack<int> &stiva, vector<int> &vizitat);
void DFSgrafTranspus(int nodPlecare, vector<vector<int>> &componente, int &nr, vector<int> &vizitat,
vector<vector<muchie>> &listaDeAdiacentaTranspusa);
};
void Graf::DFSsortareTopologica(int nodPlecare, stack<int> &stiva, vector<int> &vizitat) {
vizitat[nodPlecare] = 1;
for (auto &i: listaDeAdiacenta[nodPlecare])
if (!vizitat[i.destinatie])
DFSsortareTopologica(i.destinatie, stiva, vizitat);
stiva.push(nodPlecare);
}
void Graf::DFSgrafTranspus(int nodPlecare, vector<vector<int>> &componente, int &nr, vector<int> &vizitat,
vector<vector<muchie>> &listaDeAdiacentaTranspusa) {
vizitat[nodPlecare] = 2;
componente[nr].push_back(nodPlecare);
for (auto &i: listaDeAdiacentaTranspusa[nodPlecare])
if (vizitat[i.destinatie] == 1)
DFSgrafTranspus(i.destinatie, componente, nr, vizitat, listaDeAdiacentaTranspusa);
}
void Graf::componenteTareConexe() {
vector<vector<muchie>> listaDeAdiacentaTranspusa(nrNoduri + 1, vector<muchie>());
for (int i = 1; i <= nrNoduri; i++)
for (auto &j: listaDeAdiacenta[i])
listaDeAdiacentaTranspusa[j.destinatie].push_back(muchie(i, j.cost, j.capacitate));
vector<int> vizitat(nrNoduri + 1, 0);
vector<vector<int>> componente(nrNoduri + 1, vector<int>());
stack<int> stiva;
for (int i = 1; i <= nrNoduri; i++)
if (!vizitat[i])
DFSsortareTopologica(i, stiva, vizitat);
int nr = 0;
while (!stiva.empty()) {
int nodCurent = stiva.top();
if (vizitat[nodCurent] == 1) {
nr++;
DFSgrafTranspus(nodCurent, componente, nr, vizitat, listaDeAdiacentaTranspusa);
}
stiva.pop();
}
fout << nr << "\n";
for (int i = 1; i <= nr; i++) {
for (auto &j: componente[i])
fout << j << " ";
fout << "\n";
}
}
int main() {
int nrNoduri, nrMuchii;
fin >> nrNoduri >> nrMuchii;
Graf g1(nrNoduri, nrMuchii, true, false, false);
g1.citire();
g1.componenteTareConexe();
return 0;
}
void Graf::citire() {
int sursa, destinatie, cost, capacitate;
for (int i = 1; i <= nrMuchii; i++) {
fin >> sursa >> destinatie;
if (arePonderi)
fin >> cost;
else
cost = 0;
if (areCapacitati)
fin >> capacitate;
else
capacitate = 0;
listaDeAdiacenta[sursa].push_back(muchie(destinatie, cost, capacitate));
if (!eOrientat)
listaDeAdiacenta[destinatie].push_back(muchie(sursa, cost, capacitate));
}
}
Graf::Graf(int nrNoduri, int nrMuchii, bool eOrientat, bool arePonderi, bool areCapacitati) {
this->nrNoduri = nrNoduri;
this->nrMuchii = nrMuchii;
this->eOrientat = eOrientat;
this->arePonderi = arePonderi;
this->areCapacitati = areCapacitati;
listaDeAdiacenta.resize(nrNoduri + 1, vector<muchie>());
}