Как заметил Чарли, вы можете просто хранить сумму соответствующих размеров поддерева в каждом внутреннем узле и иметь листы, предоставляющие постоянные значения при построении (или всегда неявно использовать 1, если вас интересует только количество листьев в дереве).
Это обычно называется расширенным деревом поиска.
Интересно то, что с помощью такого рода дополнения, то есть хранения дополнительных данных для каждого узла, вы можете также получать другие виды агрегированной информации для элементов в дереве. Любая информация, которую вы можете выразить как моноид, вы можете хранить в расширенном дереве, и для этого вам нужно будет указать:
- тип данных М; в вашем примере целые числа
- бинарная операция «op» для объединения элементов, с M op M -> M; в вашем примере общий оператор «плюс»
Таким образом, помимо размеров поддерева, вы также можете выразить такие вещи, как:
- приоритетов (с помощью операторов "min" или "max"), для эффективных запросов по приоритетам min / max;
- крайние правые элементы в поддереве (т. Е. Оператор "op", который просто возвращает свой второй аргумент), при условии, что элементы, которые вы храните в дереве, упорядочены каким-либо образом. Обратите внимание, что это позволяет нам просматривать даже обычные деревья поиска (иначе словари - «сохранить это, получить этот ключ») как дополненные деревья с соответствующим моноидом.
(Эта концепция скорее напоминает кучи, или, более точно, трэпы, которые хранят случайные приоритеты с внутренними узлами для вероятностной балансировки. Она также довольно часто описывается в контексте Finger Trees, хотя это не одно и то же.)
Если вы также предоставляете нейтральный элемент для своего моноида, вы можете затем пройти по такому дереву поиска, дополненному моноидами, чтобы получить определенные элементы (например, «найдите меня 5-й лист» для вашего примера размера; «дайте мне лист» с наивысшим приоритетом ").
Хм, в любом случае. Возможно, там немного увлеклись ... Мне просто показалось, что эта тема довольно интересная. :)