На самом деле, вы можете использовать (модифицированные) RB-деревья для этого. Более того, модификация любого сбалансированного дерева (не обязательно двоичного) подойдет.
Хитрость заключается в том, чтобы хранить дополнительную информацию в каждом узле - в вашем случае это может быть общий вес поддерева, укорененного в узле, или что-то в этом роде.
Когда вы обновляете (т.е. вставляете / удаляете) дерево, вы следуете алгоритму для вашего любимого дерева. Когда вы меняете структуру, вы просто пересчитываете суммы узлов (что является операцией O (1), например, для поворотов, расщепления и соединения B-дерева). Когда вы меняете вес предмета, вы обновляете суммы предков узла.
Когда вы производите выборку, вы запускаете измененную версию поиска. Вы получаете сумму всех весов в деревьях (т.е. сумму корня) и генерируете случайное положительное число ниже, чем это. Затем вы запускаете алгоритм поиска, где вы идете к левому узлу, если число (это квантиль, который вы ищете) меньше, чем сумма левого узла. Если вы идете к правому узлу, вычтите левую сумму из квантиля.
Это описание немного хаотично, но я надеюсь, что оно поможет.