Найти в графе количество треугольников за O(E^1.5).
Будем проходиться поиском в глубину по следующему алгоритму:
- Для текущей вершины рассматриваем всех еще не посещенных соседей.
- Запускаем поиск в глубину длины два, и если вершина, в которую мы пришли на глубине два, является текущей вершиной, то прибавляем один треугольник.
- Помечаем текущую вершину как посещенную.
- Запускаемся из другой, еще не посещенной, вершины.
Таким образом, алгоритм проходит не более |V| циклом (из каждой вершины в худшем случае), причем каждое ребро в алгоритме используется ровно один раз, то есть максимальная сложность внутри цикла O(|E|). Тогда получаем сложность O(|V||E|).
Разобъем вершины на две части: в первой будут вершины степени больше, чем √E, а во второй остальные. По алгоритму выше переберем все находящиеся в первой части вершины x. Таких вершин будет не более 2√E. Тогда мы найдем все треугольники, в которых хотя бы одна из вершин степени больше √E. Сложность O(E√E).
Далее найдем все треугольники, все вершины которых имеют меньшую степень. Для этого перебираем ребра (x, y) и перебираем соседей вершины меньшей степени (которые еще проверяем на степень меньше √E). Среди этих соседей ищем ребро в другую вершину. Тогда получаем сложность Сложность E*∑min(deg(x), deg(y)), (x,y) - ребра. Тогда получаем сложность O(E√E).
Следовательно, все треугольники находим за O(E√E).
Ориентировать неор граф так, чтобы он стал сильносвязным за O(V+E), или сказать, что это невозможно.
Очевидно, что нельзя ориентировать требуемым способом граф, содержащий мосты (так как будет путь только в одну сторону), либо вовсе не являющийся связным. Тогда будем рассматривать графы без мостов, они будут реберно-двусвязными. Через обход в глубину из какой-то вершины X находим минимальное остовное дерево (тут возникает O(V + E)). Тогда достаточно будет ориентировать ребра остовного дерева по направлению к X, а остальные по направлению от X (сложность O(E)). Тогда получаем сильносвязный граф, так как мы сможем по ребрам остовного дерева в одном направлении, а по остальным в обратном, то есть из любой вершины можно будет добраться в любую другую.
Разбить все ребра неорграфа на минимальное число путей за 𝒪(𝑉 + 𝐸).
Заметим, что эта задача эквивалентна задаче о минимальном дополнении каждой компоненты связности графа до Эйлерова цикла, так как найдя Эйлеров цикл и удалив из него добавленные ребра, мы получим распавшийся на несколько новых путь. Их будет столько же, сколько ребер мы добавляли. Тогда дополним каждую компоненту связности до Эйлерова цикла, любым образом паросочетая вершины нечетной степени. Тогда получаем требуемую асимптотику O(V + E).
Для каждой пары вершин в графе найти 𝑤[𝑎, 𝑏] – такой минимальный вес, что из 𝑎 в 𝑏 есть путь по рёбрам веса <= 𝑤[𝑎, 𝑏]. O(V^2)
Построим минимальное остовное дерево через алгоритм Прима (асимптотика O(V^2) в случае плотного графа). Так как каждая вершина будет добавлена только со своим минимальным ребром (которое связывает ее с текущим MST). Тогда в полученном остовном дереве мы можем запустить поиск в ширину из каждой вершины. Тогда сложность этого будет O(V^2 + VE). Но ведь у нас дерево, где |E| <= |V|, тогда общая сложность алгоритма будет O(V^2).
Дана система из 𝑚 неравенств на 𝑛 переменных вида 𝑥 𝑖 − 𝑥 𝑗 ≤ 𝛿 𝑖𝑗 . Найти решение системы или сказать, что его не существует, за 𝒪(𝑛𝑚).
Найти в графе цикл минимального среднего веса V, E <= 2000, |w_i| <= 10**9.
Добавим к графу фиктивную вершину S и проведем из нее ребра во все остальные вершины. Далее запустим алгоритм Форда-Белмана, построив с его помощью матрицу dist[v][l] - длина минимального пути из S в V, содержащего ровно L ребер. Тогда, чтобы найти цикл минимального среднего веса, нужно посчитать min(v) max(k) (dist[v][N] - dist[v][k]) \ (N - k). Достаточно будет доказать это правило для оптимальной длины равной нулю, так как для других оптимальных длин можно просто отнять эту величину от всех ребер и получить снова случай с нулевой длиной.
Чтобы найти цикл после построения матрицы dist[v][k], запомним, при каких v и k достигается оптимальное значение, и, используя dist[v][n], будем идти по указателям к предкам. Когда достигли исходной вершины, цикл готов. Тогда итоговая сложность алгоритма O(VE).
Дан массив чисел. За 𝒪(log 𝑛) в online обрабатывать запросы: • посчитать сумму кубов чисел на отрезке [𝐿, 𝑅]; • прибавить 𝑥 ко всем числам на отрезке [𝐿, 𝑅]; • получить значение 𝑖-го числа.
Будем реализовывать дерево отрезков для суммы, но с добавлением в узлы еще двух полей - суммы кубов и суммы квадратов на отрезке. Зачем же нам нужны данные поля? При увеличении всех чисел на отрезке на b сумма кубов на данном отрезке увеличится и будет равна ∑(a_i + b)^3 = ∑(a_i)^3 + 3b∑(a_i)^2 + 3b^2∑a_i + b^3∑1. Аналогично раскрываем формулу для обновления суммы квадратов на отрезке и получаем ∑(a_i + b)^2 = ∑(a_i)^2 + 2b∑a_i + b^2∑1. Также будем хранить promise, который будем в случае необходимости пушить в детей, как и в классической реализации дерева отрезков для суммы. Тогда при обновлении отрезка будем сначала обновлять сумму кубов (так как она использует сумму квадратов и простую сумму), затем квадратов и наконец простую сумму. Тогда алгоритм работает за O(logN), как и классического дерево отрезков для суммы.
Есть массив из нулей и единиц. В online за 𝒪(log 𝑛) отвечать на запросы: поменять элемент; найти ближайший слева/справа ноль к позиции 𝑖.
Построим дерево отрезков, где узлами будут пары значений - левая и правая крайние позиции нулей на отрезке. В случае, если на отрезке нет нулей, оба значения будут равны -1. Тогда чтобы поменять элемент, нам нужно обновить узел-лист и подниматься по родителям. Тогда обновляем значения родителей до тех пор, пока оно изменяет хотя бы одно из своих значений. Запрос на ближайший ноль обрабатываем следующим образом:
- Если мы корень, то таких нулей нет.
- Поднимаемся в родителя и смотрим его второго сына: если мы пришли из левого (правого) сына, то смотрим на значение крайнего левого (крайнего правого) нуля на данном отрезке. Если такой есть, то мы нашли положение крайнего правого (левого) нуля. Если родитель - корень, и крайний левый (правый) элемент еще не найден, то он не существует.
- Повторяем П.2 до тех пор, пока не дойдем до корня.
Так как используется структура дерева отрезков, сложность операций будет O(logN).
Запросы: сумма на отрезке, прибавить 𝑎𝑖 + 𝑏 к 𝑖-у элементу отрезка [𝐿, 𝑅]. для всех 𝑖. То есть, сделать array[L + i] += a*i + b. O(log n).