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

Автор caustique, 13 лет назад, По-русски
Получил в задаче B 66 CFBR Time Limit на 9 тесте.
Сразу скажу, что у меня, возможно, не самое оптимальное решение, потому что я юзаю multiset <int> и прочие стандартные контейнеры, например vector <pair <int, string> >, хотя если убрать последний, ничего не меняется.

В дорешке переделал считывание и все сократил по минимуму - не помогло.

Посмотрел решения других участников и обнаружил у hos.lyric такое же решение, как у меня, за исключением того, что он использовал container.lower_bound(value), а я lower_bound(contaner.begin(), container.end(), value).

Его решение работает на 9 тесте 0.7 с., а мое не влезает в 4.
После переделки, решение заработало на том же тесте за 0.25 с.

Я в шоке.
Всегда думал, что эти стандартные алгоритмы эквивалентны.
Оказывается, нет?
Кто какие еще подводные камни знает в STL?
  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
вы юзали lower_bound() для сета?
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Да, это ведь отсортированный по умолчанию контейнер, ничем не хуже вектора, казалось бы.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Казалось бы iterator++ там делается за log.
      • 13 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится
        iterator++ там делается за O(1), а вот рандом аксес за линию
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          Почему за O(1)?
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            Имелось ввиду в среднем.
          • 13 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится
            нет, не в среднем, потому что там параллельно поддерживается список, и ++ и -- за O(1) происходит, покрайней мере в реализациях gcc и msvc
            • 13 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              В VC++ Express 10 стандартный алгоритм поиска prev/succ узла. То бишь, чтобы перейти из правого листа левого поддерева корня, нужно пройти его высоту. 
            • 13 лет назад, # ^ |
                Проголосовать: нравится 0 Проголосовать: не нравится
              Можно как-то подтвердить? Я очень сомневаюсь, т.к. время итерирования сета разительно отличается от линейных структур. Например, на моем нетбуке 1 млн интов итерируется за 600+ мс в сете, и за ~0 - в векторе.
              Поддержка списка реализована, если я не ошибаюсь, в структурах аля java LinkedHashSet<>.
              • 13 лет назад, # ^ |
                  Проголосовать: нравится 0 Проголосовать: не нравится
                хм, я точно не помню где я это видел, но точно помню что натыкался.

                протестировал на своей машине (Ubuntu 10.10, g++ 4.4.5) итерирование для std::list, std::vector, std::set на 10М интов, получил следующие результаты:

                0.09000 s
                0.01000 s
                0.46000 s

                соответственно, хоть небольшая, но разница есть, хотя имхо до логарифма не дотягивает
                • 13 лет назад, # ^ |
                    Проголосовать: нравится 0 Проголосовать: не нравится
                  Аммортизированная стоимость одной операции - O(1), соответственно обход дерева будет всегда O(N). Все же я удивлен, 0.46 для 10М - достаточно быстро. Так или иначе, наличие списка в set<> - это весомый элемент реализации, который не может оставаться безызвестным. Скорее все же, ты спутал с Java... :)
              • 13 лет назад, # ^ |
                  Проголосовать: нравится +5 Проголосовать: не нравится
                Вот тут написано, что set опирается на input iterator, а тут обещают, что input iterator работает за константу в среднем.
        • 13 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится
          А почему все-таки второй вариант container.lower_bound(value) работает недолго?
        • 13 лет назад, # ^ |
          Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится
          хм, спасибо, приму к сведению насчет 1
    • 13 лет назад, # ^ |
        Проголосовать: нравится +3 Проголосовать: не нравится
      У него итератор не random-access (в середину ему перейти сложно)
13 лет назад, # |
Rev. 4   Проголосовать: нравится 0 Проголосовать: не нравится
vector <pair <int, string> > =O
Вы не слышали про Map?

А по поводу сета и поиска - у меня была в точности такая же проблема...
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Интересно, зачем мне map нужен, если я меняю значение всего пару раз и доступ мне нужен за O(1)?
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
У меня ооочень похожее решение. И вообще, оно тоже должно было упасть по времени, но не упало. Для участников я использовал такой же vector< pair<int, string> > (он действительно удобней мэпа - пожно проходить по индексу), а для призов - обычный vector<int>. За минуту до конца дошло, что multiset<int> дал бы логарифм, но как оказалось и n2 (удаление из вектора) замечательно прошел =) Очевидно неполные тесты...