E074. Heavy-light декомпозиция

e-maxx algorithm original: C/C++ #algorithm #emaxx #graph
Văn bản bài toán được dịch từ tiếng Nga theo ngôn ngữ giao diện. Mã không thay đổi.

Источник: e-maxx.ru/algo, страница PDF 222.

Heavy-light декомпозиция — это достаточно общий приём, который позволяет эффективно решать многие задачи, сводящиеся к запросам на дереве. Простейший Ví dụ задач такого вида — это следующая Bài toán. given cây, каждой вершине которого

приписано какое-то number. Поступают запросы вида

, где

и

— номера вершин дерева, и it is required

узнать максимальное number на пути между vertexми

и

.

Описание Thuật toánа

Итак, пусть given cây

с

vertexми, подвешенное за некоторый корень. Суть этой декомпозиции в том, чтобы разбить cây на несколько путей таким образом, чтобы

для любой вершины

получалось, что если мы будем подниматься от

к корню, то по пути сменим не более

путей. Кроме того, все пути должны не пересекаться друг с другом по рёбрам. Понятно, что если мы научимся искать такую декомпозицию для любого дерева, это позволит свести любой запрос

вида "узнать что-то на пути из

в

" к нескольким запросам вида "узнать что-то на отрезке

-го пути".

Построение heavy-light декомпозиции

Посчитаем для каждой вершины

размер её поддерева

(т.е. это количество вершин в поддереве вершины

, включая саму вершину). Далее, рассмотрим все рёбра, ведущие к сыновьям какой-либо вершины

. Назовём edge

тяжёлым, если

оно ведёт в вершину

такую, что: Все остальные рёбра назовём лёгкими. Очевидно, что из одной вершины

вниз может исходить максимум

одно тяжёлое edge (т.к. в противном случае у вершины

было бы два сына размера

, что с учётом

самой вершины

даёт размер

, т.е. пришли к противоречию). Теперь построим саму декомпозицию дерева на непересекающиеся пути. Рассмотрим все вершины, из которых не Đầu raит вниз ни одного тяжёлого ребра, и будем идти от каждой из них вверх, пока не дойдём до корня дерева или не пройдём лёгкое edge. В результате мы получим несколько путей — покажем, что это и есть искомые пути heavy- light декомпозиции.

Chứng minh tính đúng đắn Thuật toánа

Во-первых, заметим, что полученные Thuật toánом пути будут непересекающимися. В самом деле, если бы два каких-то пути имели бы общее edge, это бы означало, что из какой-то вершины исходит вниз два тяжёлых ребра, чего быть не может. Во-вторых, покажем, что спускаясь от корня дерева до произвольной вершины, мы сменим по пути не

более

путей. В самом деле, проход вниз по лёгкому ребру уменьшает размер текущего поддерева более чем вдвое:

Таким образом, мы не могли пройти более

лёгких рёбер. Однако переходить с одного пути на другой мы

можем только через лёгкое edge (т.к. каждый путь, кроме заканчивающихся в корне, содержит лёгкое edge в конце; а попасть сразу посередине пути мы не можем). Следовательно, по пути от корня до любой вершины мы не можем сменить более

путей, что и

требовалось доказать.

Applications при решении задач

При решении задач иногда бывает удобнее рассматривать heavy-light как набор вершинно-непересекающихся путей (а не рёберо-непересекающихся). Для этого достаточно из каждого пути исключить последнее edge, если оно являются лёгким edgeм — тогда никакие свойства не нарушатся, но теперь каждая vertex будет принадлежать ровно одному пути. Ниже мы рассмотрим несколько типичных задач, которые можно решать с помощью heavy-light декомпозиции. Отдельно стоит обратить внимание на задачу сумма чисел на пути, поскольку это Ví dụ задачи, которая может быть решена и более простыми техниками.

Максимальное number на пути между двумя vertexми

given cây, каждой вершине которого приписано какое-то number. Поступают запросы вида

, где

и

номера вершин дерева, и it is required узнать максимальное number на пути между vertexми

и

. Построим заранее heavy-light декомпозицию. Над каждым получившимся путём построим Segment tree для максимума, что позволит искать вершину с максимальным приписанным numberм в указанном сегменте указанного пути

за

. Хотя number путей в heavy-light декомпозиции может достигать

, суммарный размер всех путей

есть величина

, поэтому и суммарный размер деревьев отрезков также будет линейным.

Теперь, для того чтобы отвечать на поступивший запрос

найдём наименьшего общего предка

этих

вершин (наVí dụ, методом двоичного подъёма). Теперь Bài toán свелась к двум запросам:

и

, на каждый

из которых мы можем ответить таким образом: найдём, в каком пути лежит нижняя vertex, сделаем запрос к этому пути, перейдём в вершину-конец этого пути, снова определим, в каком мы пути оказались и сделаем запрос к нему, и

так далее, пока не дойдём до пути, содержащего

.

Аккуратно следует быть со случаем, когда, наVí dụ,

и

оказались в одном пути — тогда запрос максимума к этому

пути надо делать не на суффиксе, а на внутреннем подотрезке. Таким образом, в процессе ответа на один подзапрос мы пройдём по

путям, в каждом из них сделав

запрос максимума на суффиксе или на префиксе/подотрезке (запрос на префиксе/подотрезке мог быть только один раз).

Так мы получили Lời giải за

на один запрос. Если ещё дополнительно предпосчитать на каждом пути максимумы на всех суффиксах, то получится Lời giải

за

— т.к. запрос максимума не на суффиксе случается только один раз, когда мы доходим до вершины .

Сумма чисел на пути между двумя vertexми

given cây, каждой вершине которого приписано какое-то number. Поступают запросы вида

, где

и

номера вершин дерева, и it is required узнать сумму чисел на пути между vertexми

и

. Возможен вариант этой

задачи, когда дополнительно бывают запросы изменения числа, приписанного той или иной вершине. Хотя эту задачу можно решать с помощью heavy-light декомпозиции, построив над каждым путём Segment tree для суммы (или просто предпосчитав частичные суммы, если в задаче отсутствуют запросы изменения), эта Bài toán может быть решена более простыми техниками. Если запросы модификации отсутствуют, то узнавать сумму на пути между двумя vertexми можно параллельно с поиском LCA двух вершин в Thuật toánе двоичного подъёма — для этого достаточно во время препроцессинга для

LCA подсчитывать не только

-ых предков каждой вершины, но и сумму чисел на пути до этого предка. Есть и принципиально другой подход к этой задаче — рассмотреть эйлеров обход дерева, и построить Segment tree над ним. Этот Thuật toán рассматривается в статье с Lời giảiм похожей задачи. (А если запросы модификации отсутствуют — то достаточно обойтись предпосчётом частичных сумм, без дерева отрезков.) Оба этих способа дают относительно простые решения с асимптотикой на один запрос.

Перекраска рёбер пути между двумя vertexми

given cây, каждое edge изначально покрашено в белый цвет. Поступают запросы вида

, где

и

номера вершин,

— цвет, что означает, что все рёбра на пути из

в

надо перекрасить в цвет

. it is required после

всех перекрашиваний сообщить, сколько в итоге получилось рёбер каждого цвета. Lời giải — просто сделать Segment tree с покраской на отрезке над набором путей heavy-light декомпозиции.

Каждый запрос перекраски на пути

превратится в два подзапроса

и

, где

— наименьший

общий предок вершин

и

(найденный, наVí dụ, Thuật toánом двоичного подъёма), а каждый из этих подзапросов —

в

запросов к деревьям отрезков над путями.

Итого получается Lời giải с асимптотикой

на один запрос.

Задачи в online judges

Список задач, которые можно решить, используя heavy-light декомпозицию:

● TIMUS #1553 "Caves and Tunnels" [Complexity: средняя]

● IPSC 2009 L "Let there be rainbows!" [Complexity: средняя]

● SPOJ #2798 "Query on a tree again!" [Complexity: средняя]

● Codeforces Beta Round #88 E "cây или не cây" [Complexity: высокая]

C# lời giải

bản nháp tự động, xem lại trước khi gửi
// C# draft for: Heavy-light декомпозиция
// Original e-maxx article has no compact code listing in the extracted PDF text.

C++ lời giải

đã khớp/gốc
// C++ source for: Heavy-light декомпозиция
// Compact code block was not extracted from this article.

Java lời giải

bản nháp tự động, xem lại trước khi gửi
// Java draft for: Heavy-light декомпозиция
// Original e-maxx article has no compact code listing in the extracted PDF text.

Материал разбит как Thuật toánическая Bài toán: изучить постановку, понять асимптотику и реализовать Thuật toán на выбранном языке.

Vacancies for this task

việc làm đang hoạt động with overlapping task tags are đã hiển thị.

Tất cả việc làm
Chưa có việc làm đang hoạt động.