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

Автор -14, история, 3 года назад, По-английски

Today when I took part in the Round #740 solving problem D. Top-Notch Insertions, my submission failed on test 2 without knowing why. After asserting I found that rope contains unwanted contents and I didn't fix the problem during the contest.

However, when I replace all __gnu_cxx::rope.erase(x) into __gnu_cxx::rope.erase(x, 1), my code works fine (idk if it will pass system test or not; at least, it passes asserting that all elements are rolled back to the initial state).

Then! I found it unbelievable to see the following code from here:

Look at the line 2318, comments: Erase, single character.

However, it calls erase(__p, __p + 1);, who will erase __p + 1 characters starting from the position __p.

I found it incredible since it's part of libstdc++. I don't know if there's a way to report such failure. Could anyone tell me if I can do something with it? (or instead, NEVER USE SUCH FUNCTION IN THE FUTURE)

Thank you!

UPD: I've submitted the bug to gcc.

Fortunately, it's quickly replied by Jonathan Wakely. Unfortunately, just exactly as adamant predicted, Jonathan Wakely wrotes:

We should just delete this class, so I don't have to keep fixing bugs in code that nobody uses or cares about.

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

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

I didn't even know something like Rope existed. Is this DS very useful at higher levels in CP?

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

    Generally speaking, it's a list that can random access. It can be useful when you don't want to implement a balanced search tree.

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

    To some extent. See this blog. It's terrifically slow, tho.

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

      Sure. I modified and resubmitted the code, got TLE on $$$m = 2\times 10 ^5$$$.

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

        My submission with rope passes right under the time limit with 2.729/3s, if you're interested.

        Thanks for finding this bug. I will avoid using gnu c++ stuff in the future!

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

          Cool!

          I've made a subtle change to your code, 127004930, got a 1.528s result. I remove the pop back operation and copy the whole rope at the beginning of each test case. The assignment operation is $$$O(1)$$$, since it's a persistent structure.

          But it's still quite slow. In fact, $$$2\times 10^5$$$ pop back operations had made more than $$$1$$$ second gap between two submissions. If you use one extra operation in the loop, boom -- TLE.

          So, consider prepare a splay or treap next time, if the time limit is not as optimistic as this problem.

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

            Wow, thanks!

            I never knew that assignment was $$$\mathcal{O}(1)$$$. When you say it's a persistent structure, do you mean that it creates (amortized $$$\mathcal{O}(\log (\text{size}))$$$) new nodes each time the tree is updated? Like an persistent segment tree? Sorry for asking. I can't for the life of me understand the documentation.

            And since this is a dynamic tree, I'd imagine that the code is very cancerous. :P

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

              Not amortized but strict (or in expectation?) $$$O(\log (\mathrm{size}))$$$. If I understand the document correctly, it was implemented as something like persistent treap. When you replace the character at position $$$i$$$ for example, it will split the original sequence into $$$[0, i - 1]$$$ and $$$[i + 1, n - 1]$$$, then merge $$$[0, i - 1]$$$, new character, $$$[i + 1, n - 1]$$$ into one. So it only need to implement split and merge to support all kinds of operation, both can be done in $$$O(\log (\mathrm{size}))$$$ time.

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

                Oops, I should have said high-probability $$$\mathcal{O}(\log(\text{size}))$$$ instead of amortized.

                Thank you for your help today!

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

        Shocking! Is this just again that the GCC implementation is very poor? My own contest submission passes the time limit pretty easily using Data.Sequence.Seq from the Haskell containers library, which provides a similar set of features, if I understand correctly.

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

          I guess it's because implementation is not as satisfying as we expect C++ to be. However, it's may not be author's fault. The following is my suspicion:

          1. Since rope is a persistent data structure, as a library it needs GC to recycle memory. However, GC is not natural in C++, and I noticed some long code fragments enclosed by #ifndef __GC to implement a refcount solution, which I guess make it with a large constant and lack of optimization.

          2. I am not familiar with FP languages, but I have an impression that FP compilers do heavy & fancy optimizations on data structures to improve its performance, especially on simple structures like maintaining a sequence. BTW, it may also be a way to show the FP's advantage of maintaining a persistent data structure, so it's very likely they do benchmark and focus on these structures.

          So, it's quite possible that Haskell over-perform GCC on such task, especially it's a class, by Jonathan Wakely, "nobody uses or cares about".

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

You can report it on their bugzilla (see this report on pbds, for example), but it would take years to fix and might even end up in Jonathan Wakely or smb else on libstdc++ team suggesting to deprecate these structures as they have little industrial use.

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

    I think loujunjie was the one to provide a fix there, might be you would be interested in this one?

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

    Well, if they decide to delete rope, it'd be better if they never know the bug since I want to use it (lol

    I will try to submit the bug to bugzilla. Thank you!

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

      Implement your own rope! And also make sure to make a blog about it ;)

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

    I've submitted a report to bugzilla.

    Hope to see the bug fixed in ~10 years I guess, since the last change made to the line is 17 years ago.

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

NEVER USE SUCH FUNCTION IN THE FUTURE — never use rope in the future, use treap.

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

Auto comment: topic has been updated by -14 (previous revision, new revision, compare).

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

"NEVER USE SUCH FUNCTION IN THE FUTURE"

We need a rope after a bad round though

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

I can't debug my own code but this Chinese debuged C++

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

    Sometimes you can't debug your own code because C++ itself has bugs,so you maybe need to debug C++ first before debug your own code just like this Chinese :)