Здравствуйте. Хотел бы узнать решение следующей задачи. Дан массив a[0..N-1]. Нужно отвечать на запросы двух типов, желательно за O(log^2(N)) на запрос: 1) L R x — найти кол-во различных элементов отрезка массива a[L..R], меньше либо равных x. 2) i x — изменить элемент a[i] на x. Знаю, как находить кол-во различных элементов на отрезке за O(log^2(N)) на запрос. Думал над применением похожей идеи в данной задаче, но ничего нормального так и не придумал. Какие будут идеи?
http://acm.math.spbu.ru/~sk1/mm/lections/mipt2014-sqrt/mipt-2014-burunduk1.pdf
Такое точно решается корневой декомпозицией, правда временная сложность хуже получается.
Ну с помощью корневой очевидное решение. А вот можно ли быстрее?
не так понял условие, ниже нормальное решение.
И как ты собираешься объединять ответ на разных отрезках?
Если на 1-4, у тебя числа 1-2-2-3 — три разных числа
а на 5 — 8, у тебя тоже три разных числа 3-4-4-5
То на их объединении, у тебя количество различных чисел — не их сумма. ( не 6, а 5)
не так понял условие, спасибо.
ниже норм решение
Решение за O(log^3(N)) на запрос.
Сожмем все входные данные. Храним дерево фенвика для каждого X. В каждой вершине дерева фенвика храним неявное дерево отрезков. В каждой вершине неявного дерева отрезков храним двоичное дерево поиска (например декартово дерево). Для каждого числа поддерживаем next[i] — позиция следующего такого же числа как и a[i] (или n+1 если такого нет) (как и в случае количество различных элементов на отрезке).
Запрос изменения (i, x): в дереве фенвика на суфиксе сделаем del(i,next[i]) — удалим из всех деревьев отрезков next[i], затем a[i]=x и add(i,next[i]) — добавим во все деревья отрезков наше число. Можно сказать что бы удаляем\добавляем (i, next[i]) в каждом дереве отрезков на суффиксе(но посещая при этом логарифм позиций так как это фенвик).
Запрос количества (l, r, x): присвоим x позицию в сжатом массиве, теперь ответом будет get(x, l, r) на префиксе в дереве фенвика в каждом дереве отрезков находим на отрезке с l по r количество чисел больших x (с помощью двоичного дерева поиска в каждой вершине).
уж лучше писать за sqrt(n) или даже n/64 битмасками, чем за O(log^3)
Удалено
У нас еще есть условие, что a[i] <= x
Стоит отметить, что сейчас алгоритмы с оценкой O(N·log3(N)) относятся больше к теоретическим алгоритмам. Без учета константы N·log23(N) начинает обгонять только на значениях N от 6·108. Поэтому для решения практических задач на всяких OJ такие алгоритмы не будут оптимальным решением.
Если решать задачу как "давайте поддерживать массив
next
и отвечать на 3D-запросL <= i <= R, a[i] <= x, next[i] > R
", то, видимо, для меняющегося массиваa
ничего сильно лучше O(log3n) не получится.Вот, что гуглится:
Для не меняющегося массива 3D-запрос умеют за O(logn). Это вроде классика.
Можно почитать, например, в лекциях MIT
Для меняющегося массива уже с 2D-запросом есть проблема преодолеть барьер O(log2n) => если сверху навесить дополнительное дерево отрезков, для 3D-запроса будет как раз O(log3n).
Подробно про 2D-запрос для меняющегося массива.
Гуглить нужно по словам "dynamic orthogonal range", а ещё точнее "dynamic orthogonal range counting". Есть много статей на тему "reporting" -- вывести все точки, но нас интересует только "counting" -- посчитать количество.
На выходе получаются две статьи.
a) The Cell Probe Complexity of Dynamic Range Counting (2012)
Даёт нижнюю оценку O((logn / loglogw)2) на weighted orthogonal range counting (т.е. найти не количество, а сумму)
b) Space Efficient Data Structures for Dynamic Orthogonal Range Counting [pdf] [html] (2013)
Даёт структуру данных с O(n) памяти и O((logn / loglogn)2) времени на оба запроса -- подсчёт и изменение.
P.S. Ну а за log3n с одной стороны очень медленно, с другой вроде не сложно -- дерево деревьев деревьев.
Если нужно, чтобы и код короткий, и работало быстро, есть решение за O(N0.5) без лишних логов.
Это должно быть даже чуть быстрее log2N при N ≤ 300 000.
Короткое описание решения: дерево отрезков по i, внутри корневая по запросам, внутри корневая по a[i] и next[i].
Подробно:
Когда мы научимся отвечать за n0.5 на запрос посчитать
i: a[i] <= x, next[i] > R
, то, поместив такую структуру в каждую вершину дерева отрезков по i, сможем считатьi: L <= i <= R, a[i] <= x, next[i] > R
за N0.5 + (N / 2)0.5 + (N / 4)0.5 + ... = O(N0.5). Теперь научимся отвечать на 2D запрос, n – размер конкретной вершины ДО, N – размер исходного массива.Если бы массивы a и next не менялись, можно было бы решать так. Отсортируем пары
<a[i], next[i]>
сперва по ключуa[i]
(массив X), затем по ключуnext[i]
(массив Y). Теперь каждая пара однозначно задаётся позициями в X, Y – xi, yi. Важно, что это числа из [0, n), все xi различны, все yi различны. Нарисуем точки xi, yi на плоскости, разобьём квадрат n × n на клетки k × k, где k = n0.5. Клетки образуют двухмерный массив размера (n / k) × (n / k), на котором можно предподсчитать двухмерные частичные суммы F. Когда приходит запрос на подсчётi: a[i] <= A, next[i] > R
, за O(logn) бинпоиском находим позиции A в X и R в Y, обозначим их x, y. За O(n0.5) округляем x и y к ближайшим числам кратным k. За O(1) обращаемся к F.Операция
a[i] = x
меняет две пары<a[i], next[i]>
. Перестраивать структуру не будем, вместо этого добавим в стек отложенных операций две старые точки со знаком -1 и две новые со знаком +1.Когда длина стека станет больше 2n0.5, перестроим структуру за O(n) – у нас есть отсортированный старый массив, нужно n0.5 элементов удалить, n0.5 элементов добавить.
Построение структуры в одной вершине ДО занимает O(sort + n), где sort = n, так как можно померджить детей. Итого ДО корневых строится за O(NlogN) и весит O(NlogN).
P.S. Или без лишних логов можно как-то проще?
Хорошее решение, спасибо.
deleted
Да ладно