Смена корня
Ответ для всех вершин сразу, а не только для корня. Один обход вниз, один вверх - и не надо запускать динамику n раз.
3 мин
Динамика на дереве считает ответ для корня. Но часто спрашивают ответ для каждой вершины: сумму расстояний до остальных, наибольшее удаление, число путей через вершину.
Запускать динамику из каждой вершины - : при безнадёжно. Приём смены корня (его же называют перевешиванием) считает всё за два обхода.
Идея
Подвесим дерево за вершину 0 и посчитаем обычную динамику снизу вверх: - ответ по поддереву .
Теперь заметим: если ответ для вершины уже известен, то ответ для её ребёнка отличается от него предсказуемо. Всё дерево делится ребром на две части, и при переходе от к одна часть приближается, а другая отдаляется.
Значит, второй обход - сверху вниз - пересчитывает ответ по одной формуле на ребро.
Пример: сумма расстояний
Пусть - сумма взвешенных расстояний от до всех вершин.
Первый обход даёт размеры поддеревьев и суммы внутри них:
size[v] = 1;
down[v] = 0;
for (auto [c, w] : children[v]) {
size[v] += size[c];
down[v] += down[c] + (long long)w * size[c];
}
Второй обход: , а для ребёнка вершины с весом ребра
Формула читается так: при переходе из в все вершин поддерева приблизились на , а остальные отдалились на . Разность и даёт .
Проверено: на 4000 случайных взвешенных деревьев до 9 вершин формула дала те же значения, что и запуск обхода из каждой вершины.
Когда обход вниз недостаточен
В сумме расстояний вклад «всего остального» уместился в одно число. Так бывает не всегда: если операция сборки не обратима, вычесть вклад ребёнка из уже посчитанного не получится.
Типичный пример - максимум. Пусть - ответ по части дерева вне поддерева . Тогда
и «максимум по всем детям, кроме одного» надо уметь брать быстро. Вычитание тут не работает - максимум не обратим. Стандартное решение: хранить в вершине два наибольших значения среди детей; тогда для любого ребёнка максимум по остальным - это первый максимум, если он достигнут не на нём, и второй иначе.
Общее правило: сборка должна быть либо обратимой (сумма, произведение по модулю, xor), либо допускать «всё, кроме одного» через префиксы и суффиксы по списку детей.
Схема
- Обход вниз: посчитать и всё, что нужно для перехода (размеры, два максимума).
- Обход вверх: положить и пересчитать детей по формуле.
Оба обхода стоят , память тоже. Рекурсию при лучше развернуть в явный стек: глубина дерева бывает равна .