Вопросы:
Я наткнулся на деревья Фенвика (деревья двоичных индексов), которые позволяют легко рассчитать кумулятивные суммы. Тем не менее, я нашел только реализации, в которых число уровней (слагаемых) постоянно (но их значение может меняться). Существует ли что-то похожее на обобщенное дерево Фенвика, которое позволяет изменять количество уровней (слагаемых), то есть иметь переменный размер?
Фон
В настоящее время я пишу некоторый код стохастической симуляции (на C ++): в урне есть шарики, и у каждого шарика есть определенная вероятность p_i для рисования. После события рисования шарик вытягивается (и удаляется) и заменяется двумя новыми шариками с новыми вероятностями (и все вероятности соответственно перемасштабируются; я уже делаю это «изменение масштаба» эффективно, так что не беспокойтесь об этом). В какой-то момент я начинаю удалять шарики, так что количество шариков колеблется вокруг постоянного значения (что известно ранее). Для эффективного рисования я хочу использовать двоичное дерево. Стандартное дерево Фенвика делает именно то, что я хочу, за исключением того, что оно не учитывает изменение количества шаров в урне.
Типичные цифры
Начните с 10 шариков, добавьте шарики и начните удалять шарики, когда их будет около 1000, так что в урне будет от 900 до 1100 шариков (то есть шарики добавляются и удаляются, так что число остается около 1000).
Обходной путь до сих пор
Оцените максимальное количество необходимых шариков (с некоторым запасом безопасности, скажем, 1200 шариков) и сделайте дерево Фенвика постоянного размера настолько большим, чтобы большинство шаров изначально имели вероятность 0 и были последовательно обновлены.
Большое спасибо за Вашу помощь!
Матиас
Собственно, нормальное (никак не обобщенное) дерево Фенвика позволяет в любое время увеличить количество листьев.
Некоторые конкретные реализации могут не допустить этого. Но это можно исправить. Например, реализация от TopCoder не позволяет изменить количество листьев. Проблема в том, что update
функция изменяет элементы массива, начиная с заданного индекса и повышаясь, останавливаясь при достижении некоторого предела (MaxVal
), что в нашем случае заранее неизвестно. read
Функция выполняет итерации элементов массива по убыванию, поэтому ей не нужно знать текущий размер массива. Если мы поменяем код итерации массива между update
а также read
, эта проблема может быть исправлена: сейчас update
не нужно знать MaxVal
, MaxVal
используется в read
и мы могли бы использовать самый большой обновленный индекс, насколько MaxVal
,
int read(int idx){
int sum = 0;
while (idx <= MaxVal){
sum += tree[idx];
idx += (idx & -idx);
}
return sum;
}
void update(int idx ,int val){
while (idx > 0){
tree[idx] += val;
idx -= (idx & -idx);
}
}
Заметки.
read
возвращает префиксную сумму), эта реализация дает суффиксную сумму. Если вам нужна префиксная сумма, просто вычтите значение, возвращаемое read
от общей суммы значений.BLSR
из недавнего набора инструкций Intel (BMI1).Других решений пока нет …