Cod sursa(job #3348426)

Utilizator tmxmatTudor Matasaru Mihai tmxmat Data 21 martie 2026 21:05:24
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.21 kb
#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;
}