Привет, Codeforces!
В этом посте я бы хотел поделиться тем, как я пишу Дерево отрезков, объясню, почему я это делаю классом, а так же какие у этого плюсы и минусы.
Чтобы не быть голословным я бы хотел рассмотреть свое решение на конкретной задаче (осторожно, идеи к решению)
Что в этом написании особенного
Основная моя идея в том, чтобы реализовать ДО как класс
Это позволяет использовать для двух деревьев отрезков более понятный интерфейс sgb.upd(l2, r2 + 1)
sga.upd(l1, r1 + 1)
sga.get(l1, r1 + 1) + sgb.get(l2, r2 + 1)
вместо upd1(l1, r1 +1)
upd2(l2, r2 + 1)
и get1(l1, r1 + 1) + get2(l2, r2 + 1)
А если количество деревьев переменно, то по другому это вроде не закодить(по крайней мере я не умею).
Другая не менее важная идея состоит в том, чтобы реализовать две функции каждого типа например get(int v, int l, int r, int L, int R) и get(int L, int R)
Я хочу получить значение на отрезке и не хочу думать о параметрах которые не влияют на запрос. Поэтому get(int v, int l, int r, int L, int R) является внутренним интерфейсом, который используется только для подсчета результата и не вызывается снаружи.
Так же я использую структуру, которая поддерживает приватные и публичные поля.
Это чисто эстетическое предпочтение, когда редактор подсказывает только те функции, которые могут быть вызваны снаружи. против
Почему я пишу именно так
Однажды, когда я писал отбор в сириус, была задача в которой n исходная и n ДО не совпадали. И в функции запросов и обновления я писал неверное значение n. За время отбора я так и не раздебагал это. Как итог мне не хватило совсем чуть чуть баллов до прохода. После этой грустной истории я разработал для себя некий стандарт, которому стараюсь соответствовать.
Заключение
Плюсы
- Помогает не думать над тем, какой параметр передавать в запрос (Например в приведенной выше задаче, в одном случае размер равен n/2 + 1 а в другом n/2. Подобная ошибка в пару символов может стоить нескольких минут, а в худшем случае и десятков).
- Эстетично приятно.
- Пишется шаблонно (сначала mrg, потом build, дальше push и тд).
- Легко заменить. Нужно только изменить функцию mrg и поля у вершины.
- Подходит для задач, где нужно одинаковое ДО для нескольких массивов
Минусы
- Дольше работает. Во-первых, как известно статмасивы всегда лучше векторов по скорости, однако создать класс со статмасивом лично у меня не получилось (код крашается). Во-вторых вызов функции из класса вроде работает дольше, чем обычной функции
- Дольше пишется.
Вывод
Объективно минусы существенные по сравнению с плюсами. Однако я считаю, что мой способ написания имеет место быть. Он помогает избежать ошибок при написании и использовании не очень внимательным людям (к которым я, конечно же, отношусь). Если решение получает TL заменить vec t; на pii t[MAXN] не составит большого труда. А функции в основном решении уже стоят где надо и с правильными параметрами.