Pagini recente » Borderou de evaluare (job #1588787) | Cod sursa (job #3165992) | Cod sursa (job #941111) | Borderou de evaluare (job #3302110) | Cod sursa (job #3348426)
#pragma GCC optimize("Ofast")
#include <fstream>
#include <vector>
#include <cstring>
using namespace std;
ifstream cin("ctc.in");
ofstream cout("ctc.out");
const int NMAX = 100000;
const int MMAX = 200000;
class Graph
{
private:
bool visited[NMAX + 1];
struct Edge
{
int ind;
int cost;
operator int () const
{
return ind;
}
};
vector<Edge> adj[NMAX + 1];
/// Kosaraju requirements:
vector<Edge> adj_rev[NMAX + 1];
/// Tarjan requirements:
int depth[NMAX + 1];
int low[NMAX + 1];
int n, m;
public:
vector<vector<int>> scc;
vector<Edge> adj_compact[NMAX + 1];
int roots[NMAX + 1];
void init(int n, int m)
{
this->n = n;
this->m = m;
memset(depth, 0, sizeof(depth));
memset(low, 0, sizeof(low));
}
void add_dir_edge(int src, int dest, int cost = 0)
{
adj[src].push_back({dest, cost});
}
void reverse_edges()
{
for (int i = 1; i <= n; i ++)
{
for (auto u : adj[i])
{
adj_rev[u].push_back({i, u.cost});
}
}
}
void dfs_kosaraju(int nod, vector<Edge> adja[], vector<int> &output)
{
visited[nod] = 1;
for (auto u : adja[nod])
{
if (!visited[u])
{
dfs_kosaraju(u, adja, output);
}
}
output.push_back(nod);
}
void reset_visited()
{
memset(visited, 0, sizeof(visited));
}
void get_scc_kosaraju()
{
scc.clear();
vector<int> order;
reset_visited();
for (int i = 1; i <= n; i ++)
{
if (!visited[i])
{
dfs_kosaraju(i, adj, order);
}
}
reverse_edges();
reset_visited();
for (int i = n - 1; i >= 0; i --)
{
int ind = order[i];
vector<int> component;
if (!visited[ind])
{
dfs_kosaraju(ind, adj_rev, component);
}
if (!component.empty())
{
scc.push_back(component);
int root = *component.begin();
for (auto u : component)
{
roots[u] = root;
}
}
}
for (int nod = 1; nod <= n; nod ++)
{
for (auto u : adj[nod])
{
if (roots[nod] != roots[u])
{
adj_compact[roots[nod]].push_back({roots[u], u.cost});
}
}
}
}
void dfs_tarjan(int nod, vector<Edge> adja[], vector<vector<int>> &output)
{
static vector<int> stiv;
static int time = 0;
time ++;
depth[nod] = time;
low[nod] = time;
stiv.push_back(nod);
for (auto u : adja[nod])
{
if (depth[u] == 0)
{
dfs_tarjan(u, adja, output);
low[nod] = min(low[nod], low[u]);
}
else if (roots[u] == 0)
{
low[nod] = min(low[nod], depth[u]);
}
}
if (depth[nod] == low[nod])
{
output.push_back({nod});
int u = 0;
while (nod != u)
{
u = stiv.back();
stiv.pop_back();
roots[u] = nod;
output.back().push_back(u);
}
output.back().pop_back();
}
}
void get_scc_tarjan()
{
scc.clear();
for (int nod = 1; nod <= n; nod ++)
{
if (depth[nod] == 0)
{
dfs_tarjan(nod, adj, scc);
}
}
for (int nod = 1; nod <= n; nod ++)
{
for (auto u : adj[nod])
{
if (roots[nod] != roots[u])
{
adj_compact[roots[nod]].push_back({roots[u], u.cost});
}
}
}
}
void print_edges(vector<Edge> adja[], int sz)
{
for (int i = 1; i <= sz; i ++)
{
for (auto u : adja[i])
{
cout << i << " -> " << u << " cost: " << u.cost << "\n";
}
}
}
};
int n, m;
Graph g;
void read()
{
cin >> n >> m;
for (int i = 1; i <= m; i ++)
{
int a, b;
cin >> a >> b;
g.add_dir_edge(a, b);
}
}
void process()
{
g.init(n, m);
g.get_scc_tarjan();
}
void print_result()
{
// g.print_edges(g.adj_compact, g.scc.size());
cout << g.scc.size() << "\n";
for (auto nodes : g.scc)
{
for (auto nod : nodes)
{
cout << nod << " ";
}
cout << "\n";
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
read();
process();
print_result();
return 0;
}