My first instinct was just 'run a full topological sort after adding the edge' which technically works but I second-guessed myself on whether that was efficient enough.
Precompute a topological ordering of the existing DAG, then for each candidate edge (u, v), check if u is reachable from v in the current graph. If so, adding (u, v) would create a cycle; otherwise, it's safe. Use DFS or BFS for reachability, but optimize by leveraging the topological order to prune searches.
Pro tip: Mention that you can precompute transitive closure or use bitsets for dense graphs, but for sparse graphs with 100k nodes, a single DFS per query is efficient. Also, note that if multiple queries are expected, you can precompute reachability using topological order and bitsets for O(n^2/64) time, but for a single query, O(n+m) is optimal.
Confirm that the graph is a DAG, the edge is directed, and we need to check if adding it creates a cycle. Ask about the number of queries (single vs multiple) and memory constraints.
For a single query, perform a DFS/BFS from v to see if u is reachable. If yes, adding (u, v) creates a cycle. For multiple queries, precompute reachability using topological order and bitsets or transitive closure.
Use iterative DFS to avoid recursion depth issues. If using topological order, process nodes in reverse topological order to compute reachability sets efficiently.
For single query: O(n+m) time, O(n) space. For multiple queries: O(n^2/64) time with bitsets, O(n^2/64) space. Discuss trade-offs.
Test with self-loop (u==v), edge already exists, edge from node to itself, and large graphs to ensure performance.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.