Problem:
https://codeforces.me/contest/893/problem/C
My solution:
https://codeforces.me/contest/893/submission/79402491
why does it give TLE
?
# | User | Rating |
---|---|---|
1 | tourist | 4009 |
2 | jiangly | 3823 |
3 | Benq | 3738 |
4 | Radewoosh | 3633 |
5 | jqdai0815 | 3620 |
6 | orzdevinwang | 3529 |
7 | ecnerwala | 3446 |
8 | Um_nik | 3396 |
9 | ksun48 | 3390 |
10 | gamegame | 3386 |
# | User | Contrib. |
---|---|---|
1 | cry | 167 |
2 | Um_nik | 163 |
3 | maomao90 | 162 |
3 | atcoder_official | 162 |
5 | adamant | 159 |
6 | -is-this-fft- | 158 |
7 | awoo | 156 |
8 | TheScrasse | 154 |
9 | Dominater069 | 153 |
9 | nor | 153 |
Problem:
https://codeforces.me/contest/893/problem/C
My solution:
https://codeforces.me/contest/893/submission/79402491
why does it give TLE
?
Name |
---|
It looks like you are calling std::set methods find() and erase() in your union_sets function. They are O(log N), moreover, the constant is really huge. Consider getting rid of those calls.
By the way, what you are using looks like union by size, not union by rank.
Oh, how to solve it using DSU then?
Read from here: https://cp-algorithms.com/data_structures/disjoint_set_union.html
I learned DSU from there only. And I have implemented everything correctly. The problem is TLE.
You have learned wrongly then. They use no sets. Check out the code, they only use plain arrays.
Your solution is simply not optimal. Before you read any further, I urge you to once again quickly go through your code.
Let's begin. Your logic is correct but its implementation is weak. You are storing the roots (or heads) of each disjoint set in a separate set called 'tmp'. In your Union function, you are making a total of 5 calls on this set 'tmp'. So let's make a rough estimate of the total complexity of your Union function. 2 calls for find_set (to find root) and 5 calls on 'temp' (each O(lg(n)) so it is O(7 * lg(n)). [lg(n) is log n base 2]. With given constraints, total time complexity = O(n * 7 * lg(n) + 2 * n * lg(n)) as you are initialising the set 'tmp' and finally iterating through it at the end to get answer too. When n = 10^5, then complexity = O(9 * 10^5 * lg(10^5)) , which is approximately O(1.5 * 10^7). Add to this the overhead of all these operations and you realize why you get the TLE!! In any decent problem, at most 10^6 (10^7 in rare cases) complexity is required with the most optimal solution (operations can reach 10^8 with the overhead, which is still rare). While on the surface your algorithm looks like O(n * log(n)), it's really not.
So what could you have done better? It's simple really. You need not have to keep the 'tmp' set to store the roots at all. Notice that if a vertex/node 'a' is a root, then parent[a] = a. This way you can identify your root vertex without needing to store it elsewhere. As far as the given problem is concerned, since you are only adding the minimum gold from each disjoint set, you can just store this minimum gold for the whole set in the root vertex itself. That is, gold[a] = min gold from disjoint set where a is the root vertex. The gold[v] value for other vertices which are not root (parent[v] != v) doesn't matter.
I made minimum modifications to your code to show this. It now gets AC.
DSU is one of my favourite topics and I suggest you build a template that you can quickly use. If you are interested, this is my code that I wrote when I saw your question. You can use the template if you wish to. Or you can check out submissions of top coders.
Best of luck!
Oh, I will go through your code. Yeah I will build a template for that.
Thank you so much for your time!Genuinely
can you share your dsu template? just for reference
The vector
par
holds the parent of each node, but for root node, it stores the negative of the size of the respective set. This way rooti
can be identified ifpar[i] < 0
. Furthermore,-par[i]
gives the size of that set. Using this format, you do not require an additional array to store size.You should keep things simple, I tried with DSU, here is the link
A=> parent array and other things are simple.