Hello codeforces,
I was solving this problem:
You are given a graph, and you have to answer queries of type:
1) Delete edge from U to V
2) Add edge from U to V
3) See if vertexes U and V are in the same connected component.
I couldn't come with an online solution, but I think I found an offline one.
So first I compress all queries of adding or removing and edge as: edge from U to V is available in time [i; j], where i is the time of adding and j is time of removing. Now we can do divide and conquare with dsu. This will be like that:
Rec(L, R, dsu)
{
Look for all queries that are q.L <= L and R <= q.R
([L; R] lies in [q.L; q.R]) and add unite q.U and q.V in dsu
IF L == R -> if query[L] is of type 3 then answer it and stop (and also undo changes to dsu).
Mid = (L + R) / 2;
Rec(L, Mid, dsu);
Rec(Mid + 1, R, dsu);
Undo changes to dsu
}
So this solution is O(M*logM*Cost_of_dsu). But the problem is in the DSU (the undoing of operations). I couldn't find how to do persistent DSU or DSU with restoring/undoing/backtracking. So if someone knows how to do this I will really appriciate if he helps! :)
PS: By DSU I mean disjoint set union
You may consult this.
The main idea it to have a stack of changes in dsu's arrays that have been done. In the begining of rec you remember stack size. In the end of rec, you undo operation from top of the stack while it's size is not equal to size at the beginning. The only important thing that you sholdn't do pathes compression because it have amortized complexity, so it can't be used for persistent structure. After that dsu complexity will become O(logn)
I found the implementation of the exact same idea here.
https://cp-algorithms.com/data_structures/deleting_in_log_n.html
This link is already commented by rlac 4 years ago right below your comment.
I don't think that is the same thing. The code he shared uses a persistent array, while the one I shared uses rollbacks. Rollbacks can be done in O(1) time.
thanks for magic idea <3
Here is an implementation of offline DSU.