Первый заморозок
Агроном планирует уборку и для каждого года спрашивает одно и то же: когда после 1 августа впервые выдался день со среднесуточной температурой не выше заданного порога — нуля, минус пяти, минус десяти градусов. Ряд при этом не застыл. Когда датчик ломается, испорченный участок ряда заполняют одним значением — нормой для этого сезона, — и такие замены приходят вперемешку с вопросами.
Один из тестов — настоящая среднесуточная температура Алматы с 1 января 1941 года по 31 декабря 2025-го в десятых долях градуса, 31 046 дней. Некоторые пороги в нём холоднее любого дня ряда.
Вход
В первой строке n и q (1 ≤ n ≤ 100 000, 1 ≤ q ≤ 50 000). Во второй — n целых чисел a1, …, an, |ai| ≤ 10⁹. Дальше q строк, в каждой одна операция:
= l r x— каждому из чисел al, …, ar присвоить x (1 ≤ l ≤ r ≤ n, |x| ≤ 10⁹);? l t— найти наименьшее i ≥ l, для которого ai ≤ t (1 ≤ l ≤ n, |t| ≤ 2·10⁹).
Выход
На каждый вопрос — строка с найденным номером i или −1, если такого дня нет.
Примеры
Пример 1
16 6 -21 -10 -16 -72 -115 -133 -154 -191 -182 -116 -68 -68 -99 -88 -62 -67 ? 1 -150 = 5 9 0 ? 1 -150 ? 3 -100 ? 11 -68 ? 16 -68
7 -1 10 11 -1
Пример 2
1 4 5 ? 1 5 ? 1 4 = 1 1 -5 ? 1 4
1 -1 1
Ограничения
- Время · Python
- 6000 мс
- Время · Go
- 2000 мс
- Память
- 256 МБ
- Проверка
- 8 тестов
Разбор
Открывайте по ступеням: каждая следующая подсказывает больше. Можно сразу к решению — но задача, решённая с одной подсказкой, запоминается лучше.
1Подсказка 1
Пройти по дням от l, пока не встретится холодный, просто, но если холодного дня нет до самого конца, проход длиной в весь ряд. Что нужно знать о целом куске ряда, чтобы понять, что в нём холодного дня нет?
2Подсказка 2
Минимум. Если минимум куска выше порога, весь кусок можно перепрыгнуть. Дерево отрезков хранит минимум для кусков всех размеров, и поиск может идти по нему сверху, как спуск в статье. Остаётся замена отрезка одним значением.
3Подсказка 3
Замена всех дней узла одним числом x делает минимум узла равным x — детей спрашивать не нужно. Это записка «присвоить x», которую узел отдаёт детям, когда через него проходят.
4Идея
Дерево отрезков с минимумом в узлах и отложенным присвоением. Замена отрезка ложится записками на O(log n) узлов. Вопрос — спуск: узел, который кончается раньше l или чей минимум выше t, пропускаем целиком; иначе, отдав записку детям, ищем сначала в левом ребёнке, потом в правом. Лист, до которого дошли, — ответ.
5Разбор
Решение на Go — рекурсивный спуск из статьи. Почему он быстрый: неудачный заход в узел, где минимум не выше t, но все такие дни левее l, возможен только у узлов, которые содержат l внутри, — их по одному на уровень. Узел, целиком лежащий правее l, с минимумом не выше t, наверняка содержит ответ, и из него спуск идёт одним путём до листа. Итого O(log n) узлов.
Решение на Python устроено без рекурсии и над деревом из 2k листьев: лишние листья — плюс бесконечность, они никогда не холоднее порога. Сначала записки на пути от корня к листу l проталкиваются вниз. Потом поиск идёт по блокам, из которых складывается отрезок [l, конец): от листа l вверх, пока узел — левый ребёнок, затем вправо на соседа. Каждый такой блок — правый сосед узла на пути к l, и записок над ним уже нет. Как только у блока минимум не выше t, спускаемся в него: в левого ребёнка, если там минимум не выше t, иначе в правого, проталкивая записки по дороге.
Замена отрезка — тоже без рекурсии: записки на путях к двум концам проталкиваются сверху вниз, отрезок обходится снизу вверх, взятые узлы получают значение и записку, потом предки двух концов пересчитываются снизу вверх.
5+Решение
6Сложность
Построение — O(n), каждая замена и каждый вопрос — O(log n). Проход по дням стоит O(n) на вопрос, и тесты с порогом холоднее всего ряда превращают его в q·n — миллиарды шагов. Замена срезом в Python быстрая, на C, — медленно именно искать.
7Типичные ошибки
- Проход по дням от l. На настоящей погоде он часто находит ответ за несколько недель, и кажется быстрым. Но порог холоднее всего ряда или долгая тёплая осень заставляют пройти до конца.
- Двоичный поиск по ответу с запросом минимума на [l, m]. Правильно, но O(log² n) на вопрос: работает, хотя в несколько раз медленнее спуска.
- Забыть протолкнуть записку при спуске. Узел с запиской «присвоить» знает свой минимум, а его дети — ещё нет: спуск в детей без проталкивания найдёт старый холодный день, которого уже нет.
- Нестрогое сравнение. Нужен день не выше порога, ai ≤ t: в первом примере день 11 равен порогу −68 и подходит, а день 16, −67, — нет.