</code>
Данный алгоритм работает за <tex>O(N \cdot M)</tex>, где <tex>NM</tex> {{---}} размер алфавита, <tex>MN</tex> {{---}} длина строки, что не очень быстро. Этот алгоритм можно реализовать за <tex>O(N\log(N+M))</tex>.
== Описание алгоритма за O(N log(N+M)logM) ==
Пусть дан алфавит размером <tex>M</tex> и строка <tex>S</tex> длиной <tex>N</tex>. Заведем массив <tex>\mathtt{used}Для решения будем использовать [1..N+M]</tex> и последние <tex>M</tex> ячеек заполним единицами. Запомним для каждого символа алфавита позицию в нашем массиве. Например, <tex>\mathtt{alphabet}['a'] = N+1</tex>, <tex>\mathtt{alphabet}['b'Декартово_дерево | декартово дерево] = N+2</tex>, ... , <tex>\mathtt{alphabet}['z'] = N+M</tex>.
При обработке Пусть дан алфавит размером <tex>iM</tex>-го символа посчитаем и выпишем сумму на отрезке строка <tex>[1, \mathtt{alphabet}[S[i]] - 1]</tex>, поменяем значения ячеек длиной <tex>N</tex>. Запомним для каждого символа алфавита свой ключ. Изначально <tex>\mathtt{usedkeys}[N-i+1'a']= 0</tex> и , <tex>\mathtt{used}[\mathtt{alphabetkeys}[S[i]]'b']= 1</tex> местами, также стоит поменять значение в ячейке <tex>\mathtt{alphabet}[S[i]]dots</tex> на , <tex>N\mathtt{keys}['z'] = M-i+1</tex>. Соединим все вершины в дерево по ключу.
<code>
'''list<int>''' mtf(N):
'''list<int>''' result(N)
'''list<int>''' used(N+M)minkey = 0 '''for''' i = 1 0 '''to''' M N result.append(findanswer(S[i])) <font color=darkgreen> //Заполняем последние M ячеек единицамиСчитаем ответ</font color=darkgreen> used[i+N] = 1 '''for''' i cur = 1 '''to''' N result.append(sumfind(1, alphabetkeys[S[i]] - 1)) <font color=darkgreen> //Запоминаем ответНаходим вершину в дереве </font color=darkgreen> swapsplit(used[N-i+1], used[alphabet[S[i]]]cur.key) <font color=darkgreen> //Меняем значенияВырезаем вершину из дерева</font color=darkgreen> alphabet[S[i]] min_key-- <font color= Ndarkgreen> //Уменьшаем минимально-i+1 возможный ключ</font color=darkgreen> cur.key = minkey <font color=darkgreen> //Изменяем позицию символа Ставим ключ в массивенайденной вершине на минимальный</font color=darkgreen> merge(cur, tree) <font color=darkgreen> //Объединяем нашу вершину и дерево по ключу</font color=darkgreen>
'''return''' result
</code>
Функцию Функция <tex>\mathtt{sumfindanswer}</tex> можно реализовывать по-разномусчитает ответ так: если при спуске из вершины дерева мы должны идти вправо, то прибавляем к ответу количество вершин левого поддерева + 1, иначе ничего не добавляем к ответу.
Функции <codetex> '''int''' sum(left, right) result = 0 '''for''' i = left '''to''' right result = result + used[i] '''return''' result\mathtt{split}</tex> и <tex>\mathtt{merge}</codetex>{{---}} стандартные функции для [[Декартово_дерево|декартова дерева]].
Такая реализация работает за <tex>O(right-left)\mathtt{minkey}</tex>{{---}} число, общая сложность алгоритма равна <tex>O(N \cdot M)</tex> Но можно находить сумму на отрезке при помощи [[Дерево_отрезков._Построение | которое меньше любого ключа дерева отрезков]], что сократит время работы до <tex>O(\log(right-left))</tex>. Итого, общая сложность будет равна <tex>O(N\log(N+M))</tex>
== Обратное преобразование ==
В результате сжатия получаем последовательность длиной <tex>16\cdot1 + 2\cdot2 + 3\cdot2 = 26</tex> бит. Стоит заметить, что выигрыш от применения [[Арифметическое кодирование|арифметического кодирования]] для данного примера будет еще значительней.
== См. также ==
* [[Преобразование_Барроуза-Уиллера]]
* [[Алгоритм_LZW]]
== Примечания ==