1632
правки
Изменения
м
Попробуем выполнить операцию удаления ребра. Для этого в каждой компоненте связности выделим [[Остовные деревья: определения, лемма о безопасном ребре|остовные деревья]], которые образуют остовный лес. Граф и его остовный лес {{---}} одно и то же с точки зрения связности.
[[Файл:Graph.jpg|550px|thumb|left|Произвольный граф]] [[Файл:Spanforest.jpg|550px|thumb|right|Остовный лес в графе]]
Введём функцию '''Замечание.''' Увеличив уровень ребра на единицу, нужно не забыть обновить <tex>l(e):eG_{\rightarrowi+1}[0;\mathrm{\log} n]</tex> и назовём её ''уровнем ребра'' <tex>eF_{i+1}</tex>. Будем рассматривать графы ====Оценка времени работы====Пункт <tex>G_i=\langle V, E\rangle: \{E | l(E) \geqslant i\}2</tex>. Очевидно, что работает за <tex>G_{\mathrm{O(\log}^2 n} \subseteq G_{\mathrm{\log}n-1} \subseteq \ldots \subseteq G_1 \subseteq G_0)</tex>. Выделим в них остовные леса таким образом, что так как после выхода из цикла мы добавляем ребро за <tex>F_{\mathrm{O(\log}n} \subseteq F_{\mathrm{\log}n-1} \subseteq \ldots \subseteq F_1 \subseteq F_0)</tex>на каждом уровне, где а количество уровней не больше <tex>F_i\log n</tex> {{.<!--5 сек, тут кажись я права всё-таки, нужен Лёха--}} остовный лес графа <tex>G_i</tex>.
[[Файл:Another_edgeПусть до момента, когда мы нашли нужное ребро, мы сделали <tex>S</tex> неудачных сканирований.jpg|200px|thumb|right]]После каждого такого сканирования нам приходится добавлять новые рёбра в <tex>G_{i+1}</tex>, что стоит <tex>O(\log n)</tex>. Получаем сложность удаления одного ребра <tex>O(\log^2{n}+S\cdot\log n)</tex>. <!--- Возможно, мы удалим мост, но это уже другая история, да и она всяко лучше логарифмов в квадрате... --->
При удалении возможны случаи:* '''Удаляемое ребро является мостом'''Выразим сложность одной операции <tex>\mathrm{remove}</tex> другим способом. В этом случае дерево распадается на две части (назовём их Для <tex>T(u)n</tex> вершин и <tex>Tm</tex> вызовов процедуры сложность равна <tex>O(v\log^2{n}\cdot m+\log n\cdot\displaystyle \sum_{i=1}^m S_i)</tex>), и задача решается как для дерева за что не превосходит <tex>O(\mathrmlog^2{n} \cdot m+\log n\cdot\log}n\cdot m)</tex>.* '''Удаляемое ребро не является мостом'''. Тогда существует другое ребро, соединяющее две части исходной компоненты (под частями подразумевается какое-то разбиение множества вершин на два, при этом вершины так как уровень ребра <tex>um</tex> и раз рос максимум до <tex>v\log n</tex> лежат в разных частях). Если Отсюда суммарная сложность всех запросов равна <tex>uvO(\log^2{n}\cdot m)</tex> принадлежало нашему лесу, то передаём эту "функцию" новому ребруа для одного запроса мы решаем задачу за <tex>O(\log^2{n})</tex>.
Осталось проверить, является ли ребро мостом. Будем искать ребро <tex>xy</tex> на уровне <tex>l(uv)</tex>, затем <tex>l(uv)-1</tex>, <tex>l(uv)-2</tex><tex>\ldots</tex>. Рассматривать будем меньшую из частей (будем считать, что <tex>|T(u)|\leqslant|T(v)|</tex>, в противном случае просто поменяем исследуемые вершины местами). Если мы находим такое ребро, что оно ведёт в другую часть, то останавливаемся и говорим, что <tex>uv</tex> не мост. Иначе увеличиваем уровень ребра, чтобы заново к нему не обращаться или уменьшаем уровень и повторяем процедуру. Суммарная сложность сканирования рёбер будет <tex>O(|T(u)|\mathrm{\log}n)</tex>, так как в худшем случае мы проверяем каждую вершину из <tex>T(u)</tex>, а уровень ребра не превосходит <tex>\mathrm{\log}n</tex>.====Псевдокод====
Общее время удаления одного ребра не превосходит '''function''' <tex>O(\mathrm{\logremove}^2{n}+S</tex>('''Node''' u, '''Node''' v): '''Edge''' e = <tex>\cdotlangle </tex>u, v<tex>\mathrm{rangle</tex> '''for''' i = e.level '''downto''' 0 <tex>G_i</tex> = <tex>G_i\log}nsetminus</tex>e<!---delete(<tex>G_i</tex>, e)---> <tex>F_i</tex>, где = <tex>SF_i\setminus</tex> {{e<!---}} число неудачных просмотров ребра delete(<tex>xyF_i</tex>, а для всех e)---> '''Edge''' e2 '''for''' e2 = <tex>m\langle </tex> запросов получаем x, y<tex>O(\mathrm{rangle</tex> : e2.level == i '''and''' x <tex>\log}^2{n}in T_u</tex> '''if''' y <tex>\cdot m+in T_v</tex> '''for''' j = i '''downto''' 0 <tex>F_j</tex> = <tex>F_j</tex> <tex>\mathrm{\log}n\cdot\sum{S}cup</tex> e2<!---insert(<tex>F_i</tex>, e2) \leqslant O(\mathrm--> '''return''' '''else''' e2.level++ <tex>G_{\log}^2{n} \cdot mi+\mathrm{\log1}n\cdot\mathrm{\log}n\cdot m) </tex> = O(2\cdot\mathrm<tex>G_{\log}^2{ni+1}</tex> <tex>\cdot m)cup</tex>, поэтому для одного запроса будем иметь время e2<!---insert(<tex>O(\mathrm{\log}^2{n})F_i</tex>., e2)-->
rollbackEdits.php mass rollback
}}
== Динамическая связность в лесах ==
Если задача такова, что в графе нет и не может быть циклов, то она сводится к задаче о связности в [[Деревья Эйлерова обхода|деревьях эйлерова обхода]]. Время работы каждого запроса для упрощённой задачи {{---}} <tex>O(\log n)</tex>, где <tex>n</tex> {{---}} количество вершин в графе.
== Обобщение задачи для произвольных графов ==
Существуют задачи, в которых граф не обязательно на протяжении нашей работы после каждой операции добавления ребра остаётся лесом. Добавление рёбер можно рассмотреть с точки зрения Для решения таких задач в каждой компоненте связности выделим [[СНМ (реализация с помощью леса корневых деревьев)Остовные деревья: определения, лемма о безопасном ребре|системы непересекающихся множествостовные деревья]], такой запрос будет работать за <tex>O(\mathrm{\log}n)</tex>которые образуют остовный лес. [[Файл:Graph. Операция проверки сводится к проверке связности jpg|530px|thumb|left|Граф]] [[Файл:Spanforest.jpg|530px|thumb|right|Остовный лес в остовном лесе и работает также за <tex>O(\log n)</tex>.графе]]
===Проверка связности===
Граф и его остовный лес {{---}} одно и то же с точки зрения связности. Поэтому проверка связности в графе сводится к проверке связности в остовном лесе и решается за <tex>O(\log n)</tex>.<!--Добавление рёбер можно рассмотреть с точки зрения [[СНМ (реализация с помощью леса корневых деревьев)|системы непересекающихся множеств]], такой запрос будет работать за <tex>O(\log n)</tex>. Операция проверки сводится к проверке связности в остовном лесе и работает также за <tex>O(\log n)</tex>.-->
===Добавление ребра===
Чтобы разобраться с тем, как изменится граф и остовный лес при добавлении и удалении ребра, введём функцию <tex>l(e):E{\rightarrow}[0;\log n]</tex> и назовём её ''уровнем ребра'' <tex>e</tex>. Уровни ребра можно распределить любым способом, но для всех <tex> i </tex> должно выполняться следующее свойство: размер каждой компоненты связности <tex>G_i</tex> не превосходит <tex>\dfrac{n}{2^i}</tex>. Здесь графы <tex>G_i</tex> определяются так: <tex>G_i=\langle V, E\rangle: \{e \in E \mid l(e) \geqslant i\}</tex>.
Очевидно, что <tex>G_{\log n} \subseteq G_{\log n-1} \subseteq \ldots \subseteq G_1 \subseteq G_0 = G</tex>. Выделим в графах остовные леса таким образом, что <tex>F_{\log n} \subseteq F_{\log n-1} \subseteq \ldots \subseteq F_1 \subseteq F_0</tex>, где <tex>F_i</tex> {{---}} остовный лес графа <tex>G_i</tex>.
Удобнее всего новому ребру давать уровень <tex>0</tex>. В этом случае изменится только <tex>G_0</tex>, так как в остальные подграфы <tex>G_i</tex> рёбра нулевого уровня не входят. После вставки нового ребра нам нужно проверить, были ли вершины <tex>u</tex> и <tex>v</tex> в одной компоненте связности до того, как мы вставили ребро. Если они лежали в разных компонентах, то необходимо новое ребро добавить и в остовный лес <tex>F_0</tex>.
====Псевдокод====
'''function''' <tex>\mathrm{add}</tex>('''Node''' u, '''Node''' v):
'''Edge''' e = <tex>\langle </tex>u, v<tex>\rangle</tex>
e.level = 0
<tex>G_0</tex> = <tex>G_0</tex> <tex>\cup</tex> e<!---insert(<tex>G_0</tex>, e)-->
'''if not''' <tex>\mathrm{connected(u,v)}</tex>
<tex>F_0</tex> = <tex>F_0</tex> <tex>\cup</tex> e<!---insert(<tex>F_0</tex>, e)-->
===Удаление ребра===
{{Утверждение
|statement=Если ребро, которое мы хотим удалить, не принадлежит остовному лесу, то связность между любой парой вершин сохранится.
|proof=Докажем от противного. Допустим, что это не так. Понятно, что при разрезании ребра нового пути между вершинами не появится.
Предположим, что нарушилась связность для каких-то двух вершин. Значит, мы убрали мост. А любой мост принадлежит всем остовным деревьям его компоненты. Противоречие.
}}
[[Файл:Is_there_xy.jpg|200px|thumb|right|Компонента связности T.]]
Таким образом, если мы удалили ребро не из остовного леса, то нам не придётся перестраивать лес и пересчитывать значение <tex>\mathrm{connected(u,v)}</tex>.
Рассмотрим случаи, когда мы берём ребро из леса. Тогда необходимо выяснить, является ли данное ребро мостом в графе, и выполнить соответствующие действия.
Проверим, является ли ребро мостом. У ребра <tex>uv</tex> известен уровень, пусть он равен <tex>i</tex>. Попробуем найти другое ребро (<tex>xy</tex>), соединяющее поддеревья <tex>T_u</tex> и <tex>T_v</tex>, на которые распалось остовное дерево исследуемой компоненты <tex>T</tex>.
{{Утверждение
|statement=Если ребро <tex>xy</tex> существует, то его уровень не больше <tex>i</tex>.
|proof=От противного. Пусть <tex>l(xy)=j</tex>, где <tex>j > i</tex>. Тогда вершины <tex>x</tex> и <tex>y</tex> каким-то образом связаны в <tex>F_j</tex> (либо непосредственно ребром <tex>xy</tex>, либо каким-то другим путём). Но <tex>F_j \subseteq F_i</tex>. Значит, в <tex>F_i</tex> между <tex>x</tex> и <tex>y</tex> сохранился путь из рёбер уровня не меньше <tex>j</tex> и появился другой путь через <tex>uv</tex>. Приходим к противоречию, так как в <tex>F_i</tex> все компоненты должны быть деревьями.
}}
Чтобы найти <tex>xy</tex>, выберем из поддеревьев <tex>T_u</tex> и <tex>T_v</tex> наименьшее. Не умаляя общности, будем считать, что <tex>|T_u|\leqslant|T_v|</tex>. <!--ежу понятно--> Так как всегда из двух слагаемых можно выбрать одно такое, что оно не превосходит половины их суммы, имеем важное свойство: <tex>|T_u|\leqslant\dfrac{|T_u|+|T_v|}{2}=\dfrac{|T|}{2}</tex>. Также нам известно, что <tex>T \subseteq F_i</tex>, а значит, <tex>|T|\leqslant\dfrac{n}{2^i}</tex>. Отсюда <tex>|T_u|\leqslant\dfrac{n}{2^{i+1}}</tex>. Это неравенство позволит нам увеличивать уровни рёбер при необходимости.
Будем искать ребро <tex>xy</tex> следующим образом:
# Выбираем любое ребро уровня <tex>i</tex>, выходящее из вершины, принадлежащей <tex>T_u</tex>.
# Если выбранное ребро ведёт в <tex>T_v</tex>, выходим из цикла и добавляем ребро <tex>xy</tex> в остовные леса <tex>F_i</tex>, для которых <tex>i\leqslant l(xy)</tex> и выходим из цикла;
# Если выбранное ребро ведёт в другую вершину поддерева <tex>T_u</tex>, увеличиваем его уровень на <tex>1</tex>;
# Если есть непроверенные рёбра на интересующем нас уровне <tex>i</tex>, переходим к пункту <tex>1</tex>;
# Если таких рёбер уровня <tex>i</tex> не осталось и <tex>i>0</tex>, рассматриваем уровень на единицу меньший и переходим к пункту <tex>1</tex>;
# Если все рёбра просканированы и <tex>i=0</tex>, то <tex>uv</tex> является мостом.
== См. также ==