Ответы пользователя по тегу C++
  • Скажите как можно исправить тайм лимит в коде?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Сумму на отрезке надо делать хитро: в каждой вершине поддерживайте счетчик, сумму значений всех вершин в поддереве, а так же минимальное и максимальное значение в поддереве.

    Рекурсивно спускайтесь, если текущее поддерево целиком лежит в запросе - возвращайте известную сумму.
    Иначе запускайтесь слева или справа только если отрезок там пересекается. Или можно просто возвращать 0 вместо этих проверок, если все вершины в поддереве не попадают в отрезок (меньше левой границы запроса или больше правой). Такой подход найдет сумму за O(log n) а не за O(n).
    Ответ написан
  • Более общее свойства дерева поиска?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Что за last_key? Почему дерево считается неправильным, если самая левая вершина равна numeric_limits<int>::min()

    Эта задача, в отличии от предыдущих двух ваших вопросов - простая. Тут не надо писать балансированное дерево поиска, а надо тупо проверить, что заданное дерево хорошее.

    Отличие от прошлой задачи, упомянутой в вопросе - только в том, что теперь ограничения в каждом поддереве не L < key < R, а L <= key < R. Т.е. отличие от кода в конце вопроса, по идее, должно состоять только в одном знаке <= вместо <

    Есть, правда, дополнительная проблема, что числа могут быть очень большие и, например, надо было бы в самом начале передавать numeric_limits<int>::max()+1 в качестве правой границы. Но тут можно решить эту проблему просто заменив тип параметров max_key, min_key на long long. Или изменить их смысл на "ключи в этом поддереве могут быть с L по R включительно". Тогда при переходе к левому сыну надо бы передавать tree[i].key-1 в качестве max_key. Но тогда надо аккуратно и не переполниться при numeric_limits<int>::min(). Но тут тогда нужна дополнительная проверка - любая вершина со значением numeric_limits<int>::min() не должна иметь левых детей.
    Ответ написан
    Комментировать
  • Что быстрее: создание вектора push_back или сначала объявление сколько в нем переменных, а потом заполнение?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Сначала объявление будет быстрее. Тут всего одно выделение памяти, а при push_back их будет несколько (но не n, потому что vector умный и выделяет памяти с запасом).

    Но push_back не на порядок медленнее. В худшем случае в пару раз. И то и другое будет работать за O(n). Если у вас программа еще хоть что-то делает, кроме запихивания чисел в массив, то вы разницу особо и не заметите.

    Если только профайлер не показывает что вот это вот самое медленное место в программе, то заморачиваться не стоит.
    Ответ написан
    3 комментария
  • Множество с запросами?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ваше решение медленно считает сумму на отрезке. За O(n) - вы проходитесь по всему множеству. А все ваше рение будет O(n^2). Когда как это надо делать за O(log n) максимум. Ну посмотрите же на ограничения - n <= 10^5. Обычно n^2 работает ну до 10^4 максимум с огромным скрипом и натяжками.

    К сожалению, стандартными set'ами вы сумму на отрезке быстро не подсчитаете. Придется реализовывать сбалансированное бинарное дерево поиска, где в каждой вершине надо дополнительно хранить сумму всех значений в поддереве. Вот реализация дерева, но там сумма на отрезке не реализована. Однако, в статье расказанно, как это делать. Ищите на странице "на отрезке".

    Если бы числа в задаче был поменьше, то можно было бы использовать дерево отрезков. Это сильно проще реализуется. Но тут бы это потребовало массивы на 2*10^9 элементов.

    Edit: вообще, судя по нескольким вопросам от вас, у вас там задачи именно на реализацию бинарных деревьев поиска с дополнительными данными в вершинах. Вот если у вас следующая задача опять не пройдет по времени, то сначала убедитесь, что вы используете собственноручно написанное дерево поиска.
    Ответ написан
  • Почему код не проходит по тайм лимиту?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    С такими ограничениями надо менять алгоритм. У вас наивная реализация за O(nq). А надо реализовывать rope за O(q log n).

    Какими-то стандартными контейнерами это не сделать вообще никак.

    Советую реализовывать декартово дерево по неявному ключу. Это самая простая реализация будет. Ну, а дальше вам надо будет это дерево разрезать на три части двумя Split, две крайние объеденить, разрезать это в новом месте и слить уже 3 части с вырезанным куском в середине.
    Ответ написан
  • Как работает данный алгоритм проверки числа на простоту и какой у него Big O??

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это вроде как решето Эратосфена (только с багами).

    Этот цикл по идее помечает составными все числа, делящиеся на i (которое к этому моменту вроде как простое). Таким образом все составные числа должны быть помечены в массиве a.
    Тут есть оптимизация: помечаются только те числа, для которых i - делитель не больше корня. Иначе бы цикл был не от i*i а от i. Эту оптимизацию можно делать, потому что у каждого числа обязательно есть простой делитель не больше корня, а значит и такой цикл пометит все составные числа.

    Сложность тут O(n log(log n)) - Доказательство смотрите в википедии.
    Ответ написан
    Комментировать
  • Как исправить код?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Похоже проблема в непонимании параметров string::insert. Там передается индекс, в который и вставляется строка. Т.е. новые данные будут по этому индексу. Фактически, они вставляются перед символом на этой позиции.

    Оно уже делает ровно то, что вам надо, не нужно делать там k[i]-1 и разбирать отдельно случай k[i]==0.
    Ответ написан
    Комментировать
  • Почему вылазит link error(не видит вирутальные методы?)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Потому что шаблон.

    Надо или весь класс определять в хедере, или в array.cpp указывать компилятору генерировать инстанс шаблона с параметром, который нужен в другом cpp файле:
    using Array<int>;

    То же и для очереди.

    Происходит это потому, что компилятор генерирует шаблоны лениво - только когда они нужны. Вот, компилируя array.cpp он не видет вообще ни одного использования шаблона и не генерирует ничего. В каком-нибудь main.cpp у него есть объявление из array.h и использование шаблона. Он и генерирует объявления методов. Но определения-то нигде нет. Оно в array.obj должно быть по вашему замыслу, а там пусто.
    Ответ написан
    1 комментарий
  • Почему выбивает исключение на моменте деления изображения на равные блоки?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Наверно, в коде еще есть ошибки, но вот тут:
    vector <double> variances;
    for (int i = 0; i < num_blocks; i++) {
        Scalar mean, stddev;
        meanStdDev(block[i], mean, stddev);
        variances[i] = stddev.val[0];
    }


    Вы записываете в пустой вектор variances по индексу i. Надо или делать push_back в вектор, или выделить его сразу размера num_blocks. Например, так:
    vector <double> variances(num_blocks);

    Еще перепроверьте, что у вас rows/cols не перепутано.
    Ответ написан
    Комментировать
  • Почему не считывает все нажатия вне event loop SFML?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    pollEvent возвращает сообщение из очереди, пока они там есть. В очереди их может оказаться несколько. Именно поэтому там цикл while. А код за циклом обрабатывает только одно - последнее - сообщение. Судя по наблюдаемому вами поведению, в очереди оказывается несколько сообщений.
    Ответ написан
  • Почему не работает GetPixel?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    GetPixel принимает сначала x, потом y. У вас там Height и Width не в том порядке переданы.

    Это будет ошибкой, если одна из сторон более чем в 2 раза больше другой. Это может быть, если у вас широкоформатный монитор.

    У вас там битмап сохраняется в sceen2.png - оно там что-то сохранило вообще? Иначе проблема может быть не GetPixel, а с самим хБитмапом.

    Edit:

    Еще проблема может быть с масштабированием. В результате GetSystemMetrics(SM_CYSCREEN) возвращает не то, что вам надо и BitBlt не срабатывает из-за слишком большого размера.

    Попробуйте вызвать SetProcessDPIAware.

    Еще может быть проблема, что вы SelectObject делаете 2 раза с одним и тем же membit. Надо во второй раз что-то другое подставлять, чтобы HBitmap освободить. Иначе оно, похоже, так и остается привязано к DC.

    Вот мой рабочий код:
    HBITMAP GameManager::GetScreenshot(HWND window) {
    	HDC hScreenDC = GetDC(window);
    	HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
    	RECT window_rect;
    	GetClientRect(window, &window_rect);
    	int width = window_rect.right - window_rect.left;
    	int height = window_rect.bottom - window_rect.top; 
    	int result_width = width;
    	int result_height = height;
    	
    	HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, result_width, result_height);
    	HBITMAP hOldBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hBitmap));
    	StretchBlt(hMemoryDC, 0, 0, result_width, result_height, hScreenDC, 0, 0, width, height, SRCCOPY);
    	hBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC, hOldBitmap));
    	DeleteDC(hMemoryDC);
    	DeleteDC(hScreenDC);
    	return hBitmap;
    }
    Ответ написан
    1 комментарий
  • Можно так сделать с interface?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    По уму, вам надо продумать ваш интерфейс. И тогда подобных извращений не понадобится. Дабавьте туда какой-нибудь способ для итерации по структуре данных для вывода. Или вообще сделайте метод ToString, который бы возвращал строковое представление внутренней структуры для вывода. Это все, естественно, виртуальные публичные методы, переопределенные в двух реализациях.

    То же и со вводом. Если надо как-то во внутренности очереди залезать и обычными push это не сделать, то, например, передавайте в метод CreateFromData() вектор введенных пользователем значений.
    Ответ написан
    Комментировать
  • Как сделать какую-нибудь многозадачность на ардуино?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Можно поменять логику. Включили мотор и постоянно меряете расстояние. Как домеряли до 35см - остановились.

    Можно перед циклом один раз померять - решить, а надо ли вообще мотор включать. Внутри, чтоб электричество зря не жечь, можно даже между вычислениями расстояния сколько-то спать. Смотрите там из расстояния - если оно сильно больше 35 - спите подольше.
    Ответ написан
    2 комментария
  • Почему автодополнение не предлагает мне поля структуры?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы хотите вернуть T. У Node - это член Data. Вот и возвращайте _node->data, или какой там у вас смысл у _node. Пока странно, вы наследуетесь от Array, но никак его не используете. По идее надо возвращать первый элемент в массиве.

    Да, еще, по английски правильно capaCity, а не capaSity.
    Ответ написан
  • Импликация (следование) в C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Нету в C++ отдельных операторов для этих логических функций. Потому что их все можно составить из И, ИЛИ и НЕ.

    Так, импликация - это !a || b. Эквивалентность - можно просто сравнить 2 переменные: a == b.
    Ответ написан
    1 комментарий
  • Как можно перебирать слова в C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Раз у вас во вводе коды каждого символа разделены пробелами, то все просто. Заведите в программе map<wstring, wchar> и где-то в начале напишите 33 строчки вида:
    dict[L"•−"] = L'А';

    Потом входную строку разбейте на части по проблелам. Руками, циклом. Указатель-индекс будет указывать на первый необработанный символ. Найдите первый пробел или конец строки начиная с этой позиции. Кусок между двумя позициями - это текущий код. Его с помощью map'а выше переводите в символ. Сдвигайте индекс первого необработанного символа на позицию после пробела. Ну и аккуратно смотрите, если первый необработанный - пробел, то это пробел между словами - его как есть и выводите, сдвигая индекс необработанного символа на 1.
    Ответ написан
  • Почему не вызывается конструктор копирования при инициализации переменной другим объектом?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Тут сработало copy elision.

    operator& не создает никакого временного Query, а работает сразу с Query в месте его вызова. Поэтому конструктор в пункте 8 создает уже результат.
    Ответ написан
    Комментировать
  • Что делать с этой проблемой?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Исходник в кодировке utf. 'А' действительно занимает 2 байта. Что видит компилятор? Видит 2 байта между кавычками и ругается.

    setlocale() - эта функция во время исполнения программы настроит, в какой кодировке у вас будет просиходить ввод/вывод с консоли. На кодировку исходника оно никак не влияет.

    Тут 2 варианта решения: Или поменяйте кодировку исходника и настройки локали, чтобы 'А' занимало один байт, или работайте с wstring.

    Чтобы не путаться с кодировками, напишите программу, которая выводит численное значение байт прочитанной строки. Запустите ее, введите туда 'А', смотрите, что оно выводит. Поэксперементируйте с разными настройками setlocale(). Если выводит 2 байта - вот эти два байта надо писать в case и использовать wstring. Если выводит один байт, вот его в case и вставляйте.
    Ответ написан
  • Почему выдает ошибку при наследовании?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Для решения этой проблемы по уму надо написать вот это в определении производного класса:
    using Array<T>::_size;
    using Array<T>::_capasity;
    using Array<T>::_data;


    Ответ на вопрос "почему" в С++ всегда один: "потому что стандарт":
    Non-dependent names are looked up and bound at the point of template definition. This binding holds even if at the point of template instantiation there is a better match:


    Проблема в том, что Array зависит от T, а вот его член _size от T не зависит. Ну вот не ищет компилятор независимые имена в зависимых местах. Независимые имена разрешаются в месте определения шаблона, когда еще неясно даже, с каким оно типом будет работать-то. Поэтому он никак до Array достучатся не может, ведь никакого T конкретного у него еще нет.

    Надо как-то компилятору указать, где искать вот эти ваши _size и т.д.
    Например, через this-> или через using или через Array<T>::.

    Вообще от этих правил lookup-а в C++ волосы дыбом встают и куча приколов вылезает. Их надо только запомнить. Оно неинтуитивно, но таково оно есть.
    Ответ написан
    Комментировать
  • Почему внутри шаблона можно иметь доступ к приватному члену внутреннего класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    С чего вы взяли, что внутри шаблона это работет? Вы его инстанциировать пробовали (объявить переменную класса Outer<int>, например)?

    Вылезает точно такая же ошибка.

    Если шаблон просто написать, но не использовать его, то он компилироваться и не будет и ошибки в нем не обнаружатся.
    Ответ написан
    1 комментарий