Editorial for Baltic OI '20 P3 - Joker
Submitting an official solution before solving the problem yourself is a bannable offence.
In this task, you are given a graph with nodes and edges. Furthermore, you are required to answer queries. In every query, all the edges from the interval are temporarily removed and you should check whether the graph contains an odd cycle or not.
Subtask 1
For every query do a DFS from every node and check if an odd cycle is formed.
Complexity: .
Subtask 2
The graph is bipartite if and only if it contains no odd cycle. Therefore we can color the nodes with two colors (with DFS or BFS) and check if two adjacent nodes share the same color or not.
Complexity: .
Subtask 3
We can sort the queries by their right endpoints () and answer them offline. Therefore we insert all the edges in the decreasing order of their indices into a DSU structure.
Complexity: .
Subtask 4
We can sort the queries by their left endpoint () and apply our solution from subtask 3 to all queries with the same .
Complexity: .
Subtask 5
We use the "Mo's algorithm" technique. Split the range of edge indices into blocks of size and sort the queries by or by if their left endpoint is in the same block. We can now keep two pointers to hold the current range of removed edges. If we answer all queries in the current block, the right pointer moves at most steps. The left pointer moves at most steps in total. Since the left pointer may move to the left and the right inside the current block we need to modify our DSU to allow rollbacks. If we choose we get the following runtime:
Complexity: .
Subtask 6
For any , let be the last index such that the answer for the query is positive (or if no such index exists). That is, the graph excluding the edges is bipartite, but the graph excluding the edges is not. We can prove that if , then . We will exploit this fact in order to compute the array last using a divide & conquer algorithm.
We write a recursive function , which takes two intervals: , , possibly intersecting, but and . This function will compute for each , assuming that for these values of , we have . We will initially call .
We assume that when is called, then our DSU contains all edges with indices to the left of and to the right of . For instance, when and is called, then edges with indices , , and should be in the DSU. We also assume that the graph in the DSU is bipartite.
We take and compute ; this can be done by adding all edges to the DSU, and then trying to add all edges with indices , until we try to add an edge breaking the bipartiteness. The index of such an edge is exactly . We then rollback all edges added so far in our recursive call.
Now that we know that , we will run two recursive calls:
- For each , we know that . We run , remembering to add all necessary edges to the right of . After the recursive call, we rollback them.
- For each , we know that . We run , now adding all necessary edges to the left of . We rollback them after the recursive call.
We can see that each recursive call uses at most edge additions and rollbacks in DSU, each taking time pessimistically. Also, on each level of recursion, the total length of all intervals is bounded by . Hence, all intervals in all recursive calls have total length bounded by . Hence, the total time of the preprocessing is .
With our preprocessing, each query reduces to simply verifying , which can be done in constant time.
Complexity: .
Comments