Кол-во вершин на расстоянии не более k в дереве

Revision ru10, by rafaeLL, 2025-05-29 23:38:34

Задача 1

Дано корневое дерево и число $$$k$$$. Для каждой вершины $$$u$$$ найти кол-во вершин в поддереве вершины $$$u$$$ отдаленных от $$$u$$$ на расстояние не более $$$k$$$ рёбер.

Задача 2

Дано дерево и число $$$k$$$. Для каждой вершины $$$u$$$ найти кол-во вершин во всем дереве отдаленных от $$$u$$$ на расстояние не более $$$k$$$ рёбер. (источник) (похожая задача)


В этом блоге рассмотрим решение Задачи 1 за $$$O(N)$$$. При этом используется забавная структура — RQ на stack-е с запросами $$$O(1)$$$ (по сути это будет префикс-сумма).

Вообще Задача 1 возникла при попытке (видимо не удачной) решить Задачу 2, для которой есть решения за $$$O(N \ln N)$$$, но я пока не знаком с этими темами и не хочу напутать:


Решение

Решать Задачу 1 будем через DFS. При обходе будем хранить стек чисел, каждое значение которого будет соответствовать ответу для вершины определенного поддерева. Длинна стека $$$h$$$ будет соответствовать глубине рекурсии в DFS.

  • При входе в новую вершину, увеличиваем значения в интервале стека $$$[h-k, h)$$$ на единицу. И push-ем $$$1$$$ в стек.

  • При выходе из вершины, сохраняем последнее значения стека в вершину соответствующего поддерева. И затем делам pop в стеке.

Оказывается эти операции с стеком можно выполнять за $$$O(1)$$$:

  • Для увеличения на интервале выполняем: diff[l] -= delta; diff[r] += delta;

  • При pop() выполняем "пропихивание": diff[l-1] += diff[l];

Код

После поисков нашёл задачу где используется что-то схожее — хранение пути от корня в DFS: F. Два поддерева (решение).

Хотелось бы воспользоваться rerootin-ом и с помощью Задачи 1 решить Задачу 2. Однако тогда для корня надо знать результаты для дистанций { $$$k, k-1$$$ }, чтобы подсчитать результат для дистанции { $$$k$$$ } у ребёнка. В итоге у ребёнка теряется результат для дистанции { $$$k-1$$$ }, и как его можно оптимально восстанавливать не понятно.

Удивительно, но мне как-то мало попалось статьей об этих задачах, надеюсь этот блог будет полезен!

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
ru11 Russian rafaeLL 2026-09-07 20:02:49 2708 сделал более читаемым
ru10 Russian rafaeLL 2025-05-29 23:38:34 12
ru9 Russian rafaeLL 2025-05-29 20:48:20 17
ru8 Russian rafaeLL 2025-05-29 20:45:07 2 Мелкая правка: ' мало попадалось стат' -> ' мало попалось стат'
ru7 Russian rafaeLL 2025-05-29 20:44:07 9
ru6 Russian rafaeLL 2025-05-29 20:41:06 0 (опубликовано)
ru5 Russian rafaeLL 2025-05-29 20:37:54 239 Мелкая правка: '$\n\n---\n#### Реш' -> '$\n\n---\n\n#### Реш'
ru4 Russian rafaeLL 2025-05-29 20:24:37 657
ru3 Russian rafaeLL 2025-05-29 20:06:26 593 Мелкая правка: 'n[cut]\n\n $ $\n\nПочему' -> 'n[cut]\n\n---\n\nПочему'
ru2 Russian rafaeLL 2025-05-29 19:34:35 2005 Мелкая правка: '**Задача 1.**\n> Дано корне' -> '##Задача 1.\nДано корне'
ru1 Russian rafaeLL 2025-05-29 19:22:28 1208 Первая редакция (сохранено в черновиках)