Хорошо, вы хотите, чтобы ваши данные были отсортированы, но вам нужно извлечь их через индексный номер.
Начните с базового дерева, такого как упомянутые красно-черные деревья.
Измените алгоритм дерева таким образом, чтобы при вставке элементов в дерево все узлы, встречающиеся во время вставки и удаления, сохраняли счетчик количества элементов в каждой ветви.
Затем, когда вы извлекаете данные из дерева, вы можете вычислять индекс по мере продвижения и знать, какую ветвь выбрать, основываясь на том, больше или меньше того индекса, который вы пытаетесь извлечь.
Еще одно соображение. 10M + элементов в дереве, которое использует динамическое выделение памяти, будет занимать много памяти. Т.е. указатели могут занимать больше места, чем ваши фактические данные, плюс любой другой элемент, используемый для реализации структуры данных. Это приведет к серьезной фрагментации памяти и, в худшем случае, к снижению общей производительности системы. (Передача данных назад и вперед из виртуальной памяти.) Возможно, вы захотите реализовать комбинацию распределения блоков и динамической памяти. Что-то, где вы сортируете дерево по блокам данных, тем самым уменьшая накладные расходы памяти.