Submission #1359846

#TimeUsernameProblemLanguageResultExecution timeMemory
1359846yogesh_saneSopsug (EGOI23_sopsug)C++20
100 / 100
310 ms107444 KiB
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

// Structure to handle Disjoint Set Union (DSU) logic
struct DSU {
    vector<int> parent;
    DSU(int n) {
        parent.assign(n, -1);
    }
    
    int find_root(int v) {
        if (parent[v] < 0) return v;
        return parent[v] = find_root(parent[v]);
    }
    
    bool unite(int child, int parent_node) {
        int root_child = find_root(child);
        int root_parent = find_root(parent_node);
        
        // If they are already in the same component, adding this edge creates a cycle
        if (root_child == root_parent) return false;
        
        // In this specific problem, we treat the 'parent_node' as the new representative
        parent[root_child] = root_parent;
        return true;
    }
};

// Global variables for graph state
vector<int> good_edges[300005];
set<int> forbidden_targets[300005];
set<int> unvisited_components;

void build_tree(int current_node, vector<pair<int, int>>& result_edges) {
    unvisited_components.erase(current_node);
    
    vector<int> children_to_process;
    
    // 1. Try to connect other component roots to this node
    auto it = unvisited_components.begin();
    while (it != unvisited_components.end()) {
        int candidate = *it;
        // Check if the edge (candidate -> current_node) is forbidden
        if (forbidden_targets[candidate].find(current_node) == forbidden_targets[candidate].end()) {
            children_to_process.push_back(candidate);
            // Remove from set immediately so other branches don't try to grab it
            it = unvisited_components.erase(it); 
        } else {
            ++it;
        }
    }
    
    // 2. Add the pre-existing 'good' edges that point to this node
    for (int neighbor : good_edges[current_node]) {
        children_to_process.push_back(neighbor);
        unvisited_components.erase(neighbor);
    }
    
    // 3. Record these edges and recurse
    for (int child : children_to_process) {
        result_edges.push_back({child, current_node});
    }
    for (int child : children_to_process) {
        build_tree(child, result_edges);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m, k;
    if (!(cin >> n >> m >> k)) return 0;

    DSU dsu(n);
    vector<bool> has_outgoing_edge(n, false);

    // Process required edges
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        good_edges[v].push_back(u);
        
        // A node can only have one outgoing edge in this tree
        if (has_outgoing_edge[u] || !dsu.unite(u, v)) {
            cout << "NO" << endl;
            return 0;
        }
        has_outgoing_edge[u] = true;
    }

    // Process forbidden pairs
    for (int i = 0; i < k; ++i) {
        int u, v;
        cin >> u >> v;
        forbidden_targets[u].insert(v);
    }

    // Identify roots of existing components
    vector<int> component_roots;
    for (int i = 0; i < n; ++i) {
        if (dsu.parent[i] < 0) {
            component_roots.push_back(i);
        }
    }

    // First Pass: Find a valid root for the entire tree
    for (int root : component_roots) unvisited_components.insert(root);
    
    vector<pair<int, int>> temp_edges;
    int final_root = -1;
    for (int root : component_roots) {
        if (unvisited_components.count(root)) {
            final_root = root;
            build_tree(root, temp_edges);
        }
    }

    // Second Pass: Build the final tree from that root
    unvisited_components.clear();
    for (int root : component_roots) unvisited_components.insert(root);
    
    vector<pair<int, int>> final_edges;
    build_tree(final_root, final_edges);

    // Final Validation
    if (final_edges.size() != (size_t)n - 1) {
        cout << "NO" << endl;
    } else {
        for (auto& edge : final_edges) {
            cout << edge.first << " " << edge.second << "\n";
        }
    }

    return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...