Блог пользователя stefdasca

Автор stefdasca, история, 5 лет назад, По-английски

Hi!

While I was solving some National Olympiad problems, I came up with an interesting DSU trick which can be used instead of Parallel Binary Search.

Now that I started an YouTube channel, I decided to make a video based on it.

If you enjoyed watching, please leave a like and press the subscribe button.

Also, if you know the name of this trick, please share it here or on Youtube comment section.

  • Проголосовать: нравится
  • +152
  • Проголосовать: не нравится

»
5 лет назад, # |
  Проголосовать: нравится +11 Проголосовать: не нравится

Really nice video .. looking forward to more of your upcoming videos :)

»
5 лет назад, # |
Rev. 2   Проголосовать: нравится +45 Проголосовать: не нравится

You might want to try getting a drawing tablet. It makes sketching in your pc a lot easier.

I think it's a nice gadget to have if you plan to continue making videos like this

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +76 Проголосовать: не нравится

    He might also try writing code in the IDE instead of drawing it :)

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится

      Yeah, i will do this from the next video

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +29 Проголосовать: не нравится

      there are four reasonable options actually:

      1. prepare slides
      2. write code in IDE
      3. type text in text fields in image editor like paint
      4. but a drawing tablet
  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +6 Проголосовать: не нравится

    Once COVID-19 ends, I will consider buying a drawing tablet.

    Until that point, I will probably prepare the drawings beforehand.

»
5 лет назад, # |
  Проголосовать: нравится +16 Проголосовать: не нравится

This is indeed a neat trick. As some feedback on the video, the implementation is a bit unpolished -- you wrote int x = *s[c].lower_bound(it);, but as I'm sure you know this is an error if s[c].lower_bound(it) is s[c].end(). Better would be something like if (s[c].count(it)) { ... Maybe write a reference implementation first so you can refer to it to avoid these kinds of issues.

Maybe I missed it, but you also didn't say what the complexity was? I know about the small-to-large trick but I imagine someone that doesn't know DSU wouldn't.

And (this bit is personal preference), but I usually swap() the sets so that the set corresponding to a is always s[a]. This might be a bit slower but I get easily confused if I have to keep track of a separate where array...

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    I never experienced move semantics to be slower than working with pointers. Why would you say it would be?

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится

      By "might" be, I actually meant that I don't really know whether it is or not :)

      But I've also never had any issues with it, and it's simpler to work with for me.

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +30 Проголосовать: не нравится

      FYI swap(a,b) appears to be linear for unordered_sets, while a.swap(b) is constant.

      • »
        »
        »
        »
        5 лет назад, # ^ |
          Проголосовать: нравится +21 Проголосовать: не нравится

        Interesting, according to cppreference it should be overloaded for unordered_set with constant complexity:

        https://en.cppreference.com/w/cpp/container/unordered_set/swap2

        Did you run into a linear implementation of this somewhere?

        • »
          »
          »
          »
          »
          5 лет назад, # ^ |
            Проголосовать: нравится +6 Проголосовать: не нравится

          mnbvmar discovered that recently. The following code takes a few seconds:

          Spoiler
          • »
            »
            »
            »
            »
            »
            5 лет назад, # ^ |
              Проголосовать: нравится +56 Проголосовать: не нравится

            This is a very different thing since __gnu_pbds::tree is an extension type, which is not required to have an std::swap overload by the standard. unordered_set is, so if it didn't that would be a bug.

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    The complexity is O(n log n) or O(n log^2 n), depending on the implementation.

    For example, in some cases, we can use std::vector instead of std::set, but in other cases, we can't.

»
5 лет назад, # |
  Проголосовать: нравится +13 Проголосовать: не нравится

Nice video!

I am aware of two instances of this trick, both very similar to the problem described in the video:

»
5 лет назад, # |
  Проголосовать: нравится +13 Проголосовать: не нравится

Nice video, thanks!

The same problem appeared in ECPC 2015, problem C if someone wants to submit a solution.

Another similar problem: SpbKOSHP 19 C

»
5 лет назад, # |
  Проголосовать: нравится +104 Проголосовать: не нравится

Still waiting for a comment saying that this is well known in China

  • »
    »
    5 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +12 Проголосовать: не нравится

    Well to be fair, this trick is pretty easy to come up with, the number of applicable problems is small, and there's a better/easier to implement trick called persistent dsu (not the roll-back one).

    So what I mean is, it's not well-known, but it's also not a surprise if a lot of people have already came up with this themselves.

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится

      Can you link an implementation/explanation of this persistent dsu?

      To solve the problem OP proposed, would you do a binary search for each query?

      • »
        »
        »
        »
        5 лет назад, # ^ |
        Rev. 3   Проголосовать: нравится +8 Проголосовать: не нравится

        A really similar problem. Idk if this is called persistent dsu, but the idea is to maintain the time that each link was made in the dsu tree, so the time that a and b are linked is the maximum in the path from a to b in the dsu tree, since the depth is less than log(n), we can go up in a naive manner.

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +26 Проголосовать: не нравится

    Why state the obvious?

»
5 лет назад, # |
  Проголосовать: нравится +121 Проголосовать: не нравится

...And not a single comment with a text summary.
Looks like people are ready to accept video as the base medium.
As a person who greatly prefers reading rather than watching or listening, I find it sad.

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +28 Проголосовать: не нравится

    There's a clear disadvantage to making a video about something: some people don't watch videos. I, for example, watch videos only when the content is necessarily visual, like AOE2 matches. Others don't even do that.

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится

      Yeah, that. Hard to imagine people that are good at competitive programming but don't read.

      With the current environment forcing a shift to online education, however, some of us readers may be forced to embrace the other ways to convey information.

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    I agree.

    Another argument supporting this is that in some countries (such as Cuba) internet until 2 years ago was unreasonable slow and downloading/watching videos was almost impossible. Right now, we improved a lot in downloading speed, but internet is so expensive that you might better know if downloading that video will worth it or not, so at least a text summary is quite convenient.

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится +29 Проголосовать: не нравится

    My opinion about it is evolving but right now I would say the following.

    Harder topics should be written down so that you could spend more time looking at some particular difficult fragment and analyze it (sometimes one needs a lot of time to get something complicated), and first of all you can decide if the content is useful for you or not (if you're experienced, you can make this decision). For example, I plan to make a blog "how to make fft fast" without any video.

    Easier topics should (or at least can) be videos to popularize CP and encourage more people, including casual coders and complete beginners, plus it's less formal, thus easier to understand for them. And written editorials/tutorials are oversaturated already. For example, I don't see a point in writing a CF article on binary search but I made a video for YT.

    If you disagree with something, please tell me because it will very likely affect my actions in the near future.

»
5 лет назад, # |
Rev. 2   Проголосовать: нравится +22 Проголосовать: не нравится

you didn't need to make a 23 minutes video for it

appreciate the effort, but it was unnecessarily too long

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    I decided to briefly explain DSU

    it turned out it wasn't a brief explanation, sorry for that

    About that trick, I felt like I need to explain it in detail, since I haven't seen it anywhere before(it turned out there were other problems featuring it, thanks to this blog I found this out)

    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится +6 Проголосовать: не нравится

      Hello, reflecting back, I think it was quite rude to say it like that. Sorry :( It was actually pretty good, considering those were the first videos.

      • »
        »
        »
        »
        4 года назад, # ^ |
          Проголосовать: нравится +4 Проголосовать: не нравится

        Pretty interesting to read such a comment, ngl :).

        You don't have to be sorry, criticizing that aspect of the video was alright, it helped me improve my content and as you said, it was a good video for a beginner youtuber.

»
5 лет назад, # |
Rev. 2   Проголосовать: нравится +80 Проголосовать: не нравится

LOL

photo-2020-03-30-19-19-47

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    notorious coincidence, it won't happen next time though, since I'll move to prewritten text

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      How is that a notorious coincidence though?

      • »
        »
        »
        »
        5 лет назад, # ^ |
          Проголосовать: нравится +5 Проголосовать: не нравится

        I used this term only because it's a meme popular here

        Back to a more serious reply, everyone probably knows at this point that my handwriting sucks

»
5 лет назад, # |
Rev. 2   Проголосовать: нравится +6 Проголосовать: не нравится

I got to use this trick for the first time when I was solving Problem C from ECPC 2015: Editorial

I didn't like juggling sorted vectors and dsu data back then, so I came up with an alternative implementation based on labeling edges of the dsu tree.

When we merge 2 sets' parents, we label the edge between them with their current update query time. This way, the first time 2 nodes become connected will be the maximum edge label on the path between the 2 nodes in the dsu tree. Since edge labels increase as you go up, we only care about the 2 edges connected to their LCA

»
5 лет назад, # |
  Проголосовать: нравится +21 Проголосовать: не нравится

You can enhance the complexity to $$$O(nlog(n)\alpha(n))$$$ by replacing the sets with vectors and checking if 2 nodes are in the same component with normal dsu.

Also, there's a pretty easy $$$O(log(n))$$$ per query online solution. You can iterate over the edges in input order and make a spanning tree of the edges that join new components (aka label each edge with its index and take the MST.) The answer to a query $$$(u,v)$$$ is just the maximum edge across the path $$$(u,v)$$$ in this tree. You can even answer queries online in $$$O(1)$$$ using tricks from these blogs.