Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <ctime>
- #include <iomanip>
- #include <vector>
- #include <map>
- #include <algorithm>
- #include <string>
- #include <cmath>
- #include <set>
- #include <unordered_set>
- #include <unordered_map>
- #include <stack>
- #include <cassert>
- #include <queue>
- #include <deque>
- #include <climits>
- #include <cstring>
- #include <random>
- #include <bitset>
- using namespace std;
- int n;
- vector<int> used;
- vector<int> ord;
- vector<int> colors;
- vector<vector<int>> g;
- vector<vector<int>> inv;
- vector<int> sz;
- vector<vector<int>> is_edge_scc;
- void init_reset_edge(int scc_num, const vector<unordered_set<int>> &ng) {
- is_edge_scc.assign(scc_num, vector<int> (scc_num));
- for (int i = 0; i < (int)ng.size(); i++) {
- for (auto t : ng[i]) {
- is_edge_scc[i][t] = 1;
- }
- }
- }
- void reset_edge(int u, int v, vector<unordered_set<int>> &ng) {
- is_edge_scc.at(u).at(v) = 0;
- ng[u].erase(v);
- }
- void set_edge(int u, int v, vector<unordered_set<int>> &ng) {
- is_edge_scc.at(u).at(v) = 1;
- ng[u].insert(v);
- }
- void print_edges() {
- for (int i = 0; i < (int)is_edge_scc.size(); i++) {
- for (int j = 0; j < (int)is_edge_scc.size(); j++) {
- if (is_edge_scc[i][j]) {
- cout << i + 1 << ' ' << j + 1 << '\n';
- }
- }
- }
- }
- void dfs_connected(int cur, vector<int> &used, const vector<unordered_set<int>> &ng) {
- used[cur] = 1;
- for (auto t : ng[cur]) {
- if (!used[t]) {
- dfs_connected(t, used, ng);
- }
- }
- }
- bool is_connected(int u, int v, const vector<unordered_set<int>> &ng) {
- int cu = colors[u];
- int cv = colors[v];
- vector<int> used(ng.size());
- dfs_connected(cu, used, ng);
- return used[cv];
- }
- void dfs_scc_1(int cur) {
- used[cur] = 1;
- for (auto t : g[cur]) {
- if (!used[t]) {
- dfs_scc_1(t);
- }
- }
- ord.push_back(cur);
- }
- void dfs_scc_2(int cur, int clr) {
- used[cur] = 1;
- colors[cur] = clr;
- sz[clr]++;
- for (auto t : inv[cur]) {
- if (!used[t]) {
- dfs_scc_2(t, clr);
- }
- }
- }
- vector<unordered_set<int>> scc() {
- used.assign(n, 0);
- for (int i = 0; i < n; i++) {
- if (!used[i]) {
- dfs_scc_1(i);
- }
- }
- colors.resize(n);
- used.assign(n, 0);
- reverse(ord.begin(), ord.end());
- int cnt = 0;
- for (auto t : ord) {
- if (!used[t]) {
- sz.push_back(0);
- dfs_scc_2(t, cnt);
- cnt++;
- }
- }
- vector<unordered_set<int>> ans(cnt);
- for (int i = 0; i < n; i++) {
- for (auto t : g[i]) {
- if (colors[i] != colors[t]) {
- ans[i].insert(t);
- }
- }
- }
- return ans;
- }
- int solve() {
- //get_cyclic_scc
- vector<unordered_set<int>> ng;
- ng = scc();
- init_reset_edge((int)ng.size(), ng);
- int ans_inside = 0;
- for (int i = 0; i < n; i++) {
- for (auto t : g[i]) {
- reset_edge(i, t, ng);
- auto tmp = is_connected(i, t, ng);
- if (!tmp) {
- set_edge(i, t, ng);
- ans_inside++;
- }
- }
- }
- return ans_inside;
- }
- signed main() {
- ios_base::sync_with_stdio(false);
- cin.tie(0);
- #ifdef LOCAL
- assert(freopen("input.txt", "r", stdin));
- assert(freopen("output.txt", "w", stdout));
- #endif
- int m;
- cin >> n >> m;
- g.resize(n);
- inv.resize(n);
- for (int i = 0; i < m; i++) {
- int u, v;
- cin >> u >> v;
- u--;
- v--;
- g[u].push_back(v);
- inv[v].push_back(u);
- }
- cout << solve() << endl;
- print_edges();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement