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