<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=176.215.5.216&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=176.215.5.216&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/176.215.5.216"/>
		<updated>2026-04-18T14:36:39Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%B4%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B2%D1%8F%D0%B7%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D0%BE%D1%84%D1%84%D0%BB%D0%B0%D0%B9%D0%BD&amp;diff=72633</id>
		<title>Задача о динамической связности оффлайн</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%B4%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B2%D1%8F%D0%B7%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D0%BE%D1%84%D1%84%D0%BB%D0%B0%D0%B9%D0%BD&amp;diff=72633"/>
				<updated>2020-02-12T08:05:53Z</updated>
		
		<summary type="html">&lt;p&gt;176.215.5.216: Очевидно некорректная оценка&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Имеется [[Основные_определения:_граф,_ребро,_вершина,_степень,_петля,_путь,_цикл#Неориентированные_графы|неориентированный граф]] из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; вершин, изначально не содержащий рёбер. Требуется обработать &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; запросов трёх типов:&lt;br /&gt;
* добавить ребро между вершинами &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* удалить ребро между вершинами &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;,&lt;br /&gt;
* проверить, лежат ли вершины &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в одной компоненте связности.&lt;br /&gt;
В графе могут быть кратные рёбра и петли.&lt;br /&gt;
}}&lt;br /&gt;
В этой статье приведено решение задачи в offline, то есть ответы на все запросы будут получены после обработки всех запросов, а не по мере их поступления.&lt;br /&gt;
&lt;br /&gt;
== Решение упрощённой задачи ==&lt;br /&gt;
Если нет удалений рёбер, задачу можно решить при помощи [[СНМ (реализация с помощью леса корневых деревьев)|системы непересекающихся множеств]]. Каждая компонента связности {{---}} одно множество в СНМ, и при добавлении рёбер они объединяются.&lt;br /&gt;
&lt;br /&gt;
Время работы такого решения: &amp;lt;tex&amp;gt;O(m \cdot \alpha (n))&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\alpha&amp;lt;/tex&amp;gt; {{---}} [[СНМ (реализация с помощью леса корневых деревьев)#Функция Аккермана|обратная функция Аккермана]].&lt;br /&gt;
&lt;br /&gt;
== Алгоритм ==&lt;br /&gt;
=== Построение дерева отрезков ===&lt;br /&gt;
Рассмотрим массив запросов. Каждое ребро в графе существует на некотором отрезке запросов: начиная с запроса добавления и заканчивая запросом удаления (либо концом запросов, если ребро не было удалено). Для каждого ребра можно найти этот отрезок, пройдя по массиву запросов и запоминая, когда какое ребро было добавлено.&lt;br /&gt;
&lt;br /&gt;
Пусть есть &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; рёбер, &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-е соединяет вершины &amp;lt;tex&amp;gt;v_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;u_i&amp;lt;/tex&amp;gt;, было добавлено запросом &amp;lt;tex&amp;gt;L_i&amp;lt;/tex&amp;gt; и удалено запросом &amp;lt;tex&amp;gt;R_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Построим на массиве запросов [[Дерево отрезков. Построение|дерево отрезков]], в каждой его вершине будем хранить список пар. &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-е рёбро графа нужно добавить на отрезок &amp;lt;tex&amp;gt;[L_i,R_i]&amp;lt;/tex&amp;gt;. Это делается аналогично тому, как в дереве отрезков происходит добавление на отрезке (процесс описан в статье &amp;quot;[[Несогласованные поддеревья. Реализация массового обновления]]&amp;quot;), но без &amp;lt;tex&amp;gt;push&amp;lt;/tex&amp;gt;: нужно спуститься по дереву от корня и записать пару &amp;lt;tex&amp;gt;u_i,v_i&amp;lt;/tex&amp;gt; в вершины дерева отрезков.&lt;br /&gt;
&lt;br /&gt;
Теперь чтобы узнать, какие рёбра существуют во время выполнения &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-го запроса, достаточно посмотреть на путь от корня дерева отрезков до листа, который соответствует этому запросу {{---}} рёбра, записанные в вершинах этого пути, существуют во время выполнения запроса.&lt;br /&gt;
&lt;br /&gt;
=== Ответы на запросы ===&lt;br /&gt;
Обойдём дерево отрезков в глубину, начиная с корня. Будем поддерживать граф, состоящий из рёбер, которые содержатся на пути от текущей вершины дерева отрезков до корня. При входе в вершину добавим в граф рёбра, записанные в этой вершине. При выходе из вершины нужно откатить граф к состоянию, которое было при входе. Когда мы добираемся до листа, в граф уже добавлены все рёбра, которые существуют во время выполнения соответствующего запроса, и только они. Поэтому если этот лист соответствует запросу третьего типа, его следует выполнить и сохранить ответ.&lt;br /&gt;
&lt;br /&gt;
Для поддержания такого графа и ответа на запросы будем использовать [[СНМ (реализация с помощью леса корневых деревьев)|систему непересекающихся множеств]]. При добавлении рёбер в граф объединим соответствующие множества в СНМ. Откатывание состояния СНМ описано ниже.&lt;br /&gt;
&lt;br /&gt;
=== СНМ с откатами ===&lt;br /&gt;
Для того, чтобы иметь возможность откатывать состояние СНМ, нужно при каждом изменении любого значения в СНМ записывать в специальный массив, что именно изменилось и какое было предыдущее значение. Это можно реализовать как массив пар (указатель, значение).&lt;br /&gt;
&lt;br /&gt;
Чтобы откатить состояние СНМ, пройдём по этому массиву в обратном порядке и присвоим старые значения обратно. Для лучшего понимания ознакомьтесь с приведённой ниже реализацией.&lt;br /&gt;
&lt;br /&gt;
Нужно заметить, что эвристику сжатия путей в этом случае применять не следует. Эта эвристика улучшает асимптотическое время работы, но это время работы не истинное, а амортизированное. Из-за наличия откатов к предыдущим состояниям эта эвристика не даст выигрыша. СНМ с ранговой эвристикой же работает за &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; на запрос истинно.&lt;br /&gt;
&lt;br /&gt;
Запоминание изменений и откаты не влияют на время работы, если оно истинное, а не амортизированное. Действительно: пусть в СНМ произошло &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; изменений. Каждое из них будет один раз занесено в массив и один раз отменено. Значит, запись в массив и откаты работают за &amp;lt;tex&amp;gt;\Theta(r)&amp;lt;/tex&amp;gt;. Но и сами изменения заняли &amp;lt;tex&amp;gt;\Theta(r)&amp;lt;/tex&amp;gt; времени, значит, откаты не увеличили асимптотическое время работы.&lt;br /&gt;
&lt;br /&gt;
Вместо описанного способа откатывания состояния СНМ можно использовать [[Персистентные структуры данных|персистентный]] СНМ, но этот вариант сложнее и имеет меньшую эффективность. &amp;lt;!-- Я не уверен, бывает ли персистентный СНМ, работающий за log. --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Время работы ==&lt;br /&gt;
Каждое из &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt; рёбер записывается в &amp;lt;tex&amp;gt;O(\log m)&amp;lt;/tex&amp;gt; вершин дерева отрезков. Поэтому операций &amp;lt;tex&amp;gt;\mathrm{union}&amp;lt;/tex&amp;gt; в СНМ будет &amp;lt;tex&amp;gt;O(m \log m)&amp;lt;/tex&amp;gt;. Каждая выполняется за &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; (СНМ с ранговой эвристикой). Откаты не влияют на время работы.&lt;br /&gt;
&lt;br /&gt;
Можно считать, что &amp;lt;tex&amp;gt;n = O(m)&amp;lt;/tex&amp;gt;, так как в запросах используется не более &amp;lt;tex&amp;gt;2m&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
Время работы: &amp;lt;tex&amp;gt;O(m \log m \log n) = O(m \log^2 m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Реализация на C++ ==&lt;br /&gt;
 '''#include''' &amp;lt;bits/stdc++.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''using''' '''namespace''' std;&lt;br /&gt;
 '''typedef''' pair &amp;lt; '''int''' , '''int''' &amp;gt; ipair;&lt;br /&gt;
 '''const''' '''int''' N = 100321;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// СНМ&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int''' dsuP[N], dsuR[N];&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// В этот массив записываются все изменения СНМ, чтобы их можно откатить&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// При изменении какого-то значения в СНМ в hist записывается пара &amp;lt; указатель, старое значение &amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
 vector &amp;lt; pair &amp;lt; '''int'''*, '''int''' &amp;gt; &amp;gt; hist;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Для элемента из СНМ возвращает корень дерева, в котором он находится&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int''' dsuRoot('''int''' v)&lt;br /&gt;
 {&lt;br /&gt;
     '''while''' (dsuP[v] != -1)&lt;br /&gt;
         v = dsuP[v];&lt;br /&gt;
     '''return''' v;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Объединяет два множества. Используется ранговая эвристика.&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// При любом изменении содержимого массивов dsuP и dsuR&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// в hist записывается адрес и старое значение&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''void''' dsuMerge('''int''' a, '''int''' b)&lt;br /&gt;
 {&lt;br /&gt;
     a = dsuRoot(a);&lt;br /&gt;
     b = dsuRoot(b);&lt;br /&gt;
     '''if''' (a == b)&lt;br /&gt;
         '''return''';&lt;br /&gt;
     '''if''' (dsuR[a] &amp;gt; dsuR[b])&lt;br /&gt;
     {&lt;br /&gt;
         hist.emplace_back(&amp;amp;dsuP[b], dsuP[b]);&lt;br /&gt;
         dsuP[b] = a;&lt;br /&gt;
     } '''else''' '''if''' (dsuR[a] &amp;lt; dsuR[b])&lt;br /&gt;
     {&lt;br /&gt;
         hist.emplace_back(&amp;amp;dsuP[a], dsuP[a]);&lt;br /&gt;
         dsuP[a] = b;&lt;br /&gt;
     } '''else'''&lt;br /&gt;
     {&lt;br /&gt;
         hist.emplace_back(&amp;amp;dsuP[a], dsuP[a]);&lt;br /&gt;
         hist.emplace_back(&amp;amp;dsuR[b], dsuR[b]);&lt;br /&gt;
         dsuP[a] = b;&lt;br /&gt;
         ++dsuR[b];&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 '''struct''' Query&lt;br /&gt;
 {&lt;br /&gt;
     '''int''' t, u, v;&lt;br /&gt;
     bool answer;&lt;br /&gt;
 };&lt;br /&gt;
 '''int''' n, m;&lt;br /&gt;
 Query q[N];&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Дерево отрезков, в каждой вершине которого хранится список рёбер&amp;lt;/font&amp;gt;&lt;br /&gt;
 vector &amp;lt; ipair &amp;gt; t[N*4];&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Эта функция добавляет ребро на отрезок&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// [l r] - отрезок, на который добавляется ребро&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// uv - ребро, c - текущая вершина дерева отрезков,&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// [cl cr] - отрезок текущей вершины дерева отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''void''' addEdge('''int''' l, '''int''' r, ipair uv, '''int''' c, '''int''' cl, '''int''' cr)&lt;br /&gt;
 {&lt;br /&gt;
     '''if''' (l &amp;gt; cr || r &amp;lt; cl)&lt;br /&gt;
         '''return''';&lt;br /&gt;
     '''if''' (l &amp;lt;= cl &amp;amp;&amp;amp; cr &amp;lt;= r)&lt;br /&gt;
     {&lt;br /&gt;
         t[c].push_back(uv);&lt;br /&gt;
         '''return''';&lt;br /&gt;
     }&lt;br /&gt;
     '''int''' mid = (cl + cr) / 2;&lt;br /&gt;
     addEdge(l, r, uv, c*2+1, cl, mid);&lt;br /&gt;
     addEdge(l, r, uv, c*2+2, mid+1, cr);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Обход дерева отрезков в глубину&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''void''' go('''int''' c, '''int''' cl, '''int''' cr)&lt;br /&gt;
 {&lt;br /&gt;
     '''int''' startSize = hist.size();&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Добавляем рёбра при входе в вершину&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''for''' (ipair uv : t[c])&lt;br /&gt;
         dsuMerge(uv.first, uv.second);&lt;br /&gt;
 &lt;br /&gt;
     '''if''' (cl == cr)&lt;br /&gt;
     {&lt;br /&gt;
         &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Если эта вершина - лист, то отвечаем на запрос&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''if''' (q[cl].t == 3)&lt;br /&gt;
             q[cl].answer = (dsuRoot(q[cl].u) == dsuRoot(q[cl].v));&lt;br /&gt;
     } '''else''' {&lt;br /&gt;
         '''int''' mid = (cl + cr) / 2;&lt;br /&gt;
         go(c*2+1, cl, mid);&lt;br /&gt;
         go(c*2+2, mid+1, cr);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Откатываем изменения СНМ&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''while''' (('''int''')hist.size() &amp;gt; startSize)&lt;br /&gt;
     {&lt;br /&gt;
         *hist.back().first = hist.back().second;&lt;br /&gt;
         hist.pop_back();&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 '''int''' main()&lt;br /&gt;
 {&lt;br /&gt;
     ios::sync_with_stdio('''false''');&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Формат входных данных:&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// n и m, затем в m строках запросы: по три числа t, u, v&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// t - тип (1 - добавить ребро, 2 - удалить, 3 - принадлежат ли одной компоненте)&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Нумерация вершин с нуля&amp;lt;/font&amp;gt;&lt;br /&gt;
     cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m;&lt;br /&gt;
     '''for''' ('''int''' i = 0; i &amp;lt; n; ++i) &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Инициализация СНМ&amp;lt;/font&amp;gt;&lt;br /&gt;
         dsuP[i] = -1;&lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// В этом массиве для каждого ещё не удалённого ребра хранится&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// на каком запросе оно было создано&amp;lt;/font&amp;gt;&lt;br /&gt;
     set &amp;lt; pair &amp;lt; ipair, '''int''' &amp;gt; &amp;gt; edges;&lt;br /&gt;
     '''for''' ('''int''' i = 0; i &amp;lt; m; ++i)&lt;br /&gt;
     {&lt;br /&gt;
         cin &amp;gt;&amp;gt; q[i].t &amp;gt;&amp;gt; q[i].u &amp;gt;&amp;gt; q[i].v;&lt;br /&gt;
         &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Поскольку рёбра неориентированные, u v должно означать то же самое, что и v u&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''if''' (q[i].u &amp;gt; q[i].v) swap(q[i].u, q[i].v);&lt;br /&gt;
         &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// При добавлении ребра кладём его в set&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''if''' (q[i].t == 1)&lt;br /&gt;
             edges.emplace(ipair(q[i].u, q[i].v), i);&lt;br /&gt;
         &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// При удалении ребра берём из set время его добавления - так мы узнаём отрезок заросов,&amp;lt;/font&amp;gt;&lt;br /&gt;
         &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// на котором оно существует. Если есть несколько одинаковых рёбер, можно брать любое.&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''else''' '''if''' (q[i].t == 2)&lt;br /&gt;
         {&lt;br /&gt;
             '''auto''' iter = edges.lower_bound(make_pair(ipair(q[i].u, q[i].v), 0));&lt;br /&gt;
             addEdge(iter-&amp;gt;second, i, iter-&amp;gt;first, 0, 0, m - 1);&lt;br /&gt;
             edges.erase(iter);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Обрабатываем рёбра, которые не были удалены&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''for''' ('''auto''' e : edges)&lt;br /&gt;
         addEdge(e.second, m - 1, e.first, 0, 0, m - 1);&lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Запускаем dfs по дереву отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
     go(0, 0, m - 1);&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// Выводим ответ.&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// При обходе дерева отрезков запросы обрабатываются в том же порядке, в котором они даны,&amp;lt;/font&amp;gt;&lt;br /&gt;
     &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// поэтому ответ можно выводить прямо в go без заполнения answer&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''for''' ('''int''' i = 0; i &amp;lt; m; ++i)&lt;br /&gt;
         '''if''' (q[i].t == 3)&lt;br /&gt;
         {&lt;br /&gt;
             '''if''' (q[i].answer)&lt;br /&gt;
                 cout &amp;lt;&amp;lt; &amp;quot;YES\n&amp;quot;;&lt;br /&gt;
             '''else'''&lt;br /&gt;
                 cout &amp;lt;&amp;lt; &amp;quot;NO\n&amp;quot;;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     '''return''' 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Замечания ==&lt;br /&gt;
* Дерево отрезков можно строить не на всех запросах, а только на запросах третьего типа. Это даст выигрыш по скорости и памяти, особенно если таких запросов немного по сравнению с общим числом запросов.&lt;br /&gt;
* Помимо проверки, лежат ли две вершины в одной компоненте связности, можно получать и другую информацию, которую можно получить из СНМ, напрмер:&lt;br /&gt;
** Размер компоненты связности, которая содержит вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;&lt;br /&gt;
** Количество компонент связности&lt;br /&gt;
* Эту идею можно использовать и для других задач. Вместо СНМ можно использовать любую структуру данных, в которую можно добавлять, но не удалять.&lt;br /&gt;
** Например, динамический рюкзак: добавлять предмет в него можно за &amp;lt;tex&amp;gt;O(w)&amp;lt;/tex&amp;gt; (&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; {{---}} максимальный вес), а удалять нельзя. Аналогично тому, как в dynamic connectivity offline добавляются и удаляются рёбра, можно удалять элементы из рюкзака.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[СНМ (реализация с помощью леса корневых деревьев)|Система непересекающихся множеств]]&lt;br /&gt;
* [[Дерево отрезков. Построение|Дерево отрезков]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Связность в графах]]&lt;/div&gt;</summary>
		<author><name>176.215.5.216</name></author>	</entry>

	</feed>