# e-olymp 93. Truck driving

Umidsh Izadish is a truck driver and wants to drive from a city to another city while there exists a dedicated straight road between each pair of cities in that country. Amount of consumed fuel is the distance between two cities which is computed from their coordinates. There is a gas station in each city, so Umidsh can refuel the gas container of his truck. Your job is to compute the minimum necessary volume of gas container of Umidsh’s Truck.

## Input data

The first line of input contains an integer, the number of test cases. Following, there are data for test cases. Each test case begins with a line containing one integer, $C$ $(2 ≤ C ≤ 200)$, which is the number of cities. The next $C$ lines each contain two integers $x$, $y$ $(0 ≤ x, y≤ 1000)$ representing the coordinate of one city. First city is the source city and second is the destination city of Umidsh.

## Output data

There should be one line for each test case in output. Each line should contain one floating point number which is the minimum necessary volume of truck’s gas container, printed to three decimals.

## Tests

 Input Output $2$ $2$ $0$ $0$ $3$ $4$ $3$ $17$ $4$ $19$ $4$ $18$ $5$ $5.000$ $1.414$ $1$ $3$ $4$ $5$ $4$ $6$ $4$ $7$ $1.000$ $2$ $4$ $0$ $1$ $0$ $-1$ $1$ $0$ $-1$ $0$ $3$ $8$ $9$ $0$ $1$ $14$ $14$ $1.414$ $11.314$ $3$ $2$ $1$ $1$ $1$ $2$ $5$ $8$ $6$ $3$ $3$ $4$ $1$ $7$ $7$ $5$ $0$ $3$ $1$ $1$ $1$ $3$ $2$ $5$ $1.000$ $5.657$ $2.000$

## Solution

We can interpretate the set of the cities as weighted graph, which vertices represent cities and weight of each edge between two vertices is the gas volume required for passing the distance between corresponding cities.
The volume of truck’s gas container depends on the gas volume required for arrival to the each next station of the Umidsh’s way. The maximum between gas volume required to get to the city $A$ and gas volume required to pass the way from the city $A$ to the city $B$ represents the minimum necessary gas volume required to get to the city $B$ through the city $A$. So the volume of truck’s gas container would turn to minimum, when the maximum gas volume required for passing the distance between each two stations of his way would turn to minimum. Thus we could use modified Dijkstra’s algorithm to find the biggest value among the weights of an edges between each two stations of the way between vertice 0 and vertice 1.

# e-olymp 4493. Трое из Простоквашино 3

Задача

$-$ Печкин, а я научился работать с деревом отрезков.

$-$ Заняться тебе нечем просто, Шарик. Лучше бы помог мне письма разносить.

$-$ Ну, Печкин, я уже даже выполнил задания Дяди Федора и Кота Матроскина, только этот Матроскин не захотел проверять, правильно ли я сделал.

$-$ Ну ладно, давай я проверю, что там надо было сделать?

$-$ У меня был массив чисел и множество запросов – представляющих собой либо запрос на изменение в массиве, либо содержащий число, для которого мне нужно было найти такой промежуток [$l;r$], что максимум на этом промежутке был бы равен заданному числу. Можешь прочитать предыдущую задачу.

$-$ Разберемся…

Входные данные

В первой строке содержится одно число $N$ ($1≤N≤106$) – количество элементов в массиве. В следующей строке находится $N$ целых, неотрицательных чисел, не превосходящих 109 – сами элементы массива. Затем следует число $M$ ($1≤M≤105$) – количество запросов. Затем $М$ строк, первое число в каждой из которых означает тип запроса: если оно равно единице, то далее следует единственное число $x$, и Шарику надо было найти два числа $l$ и $r$, такие, что максимум на промежутке [$l;r$], был равен $x$. Если же тип запроса равен двум, то далее следует два числа $pos$ и $val$ и это значит, что элемент массива, стоящий на позиции $pos$, теперь изменен и он стал равен значению $val$. Далее для каждого запроса с номером один содержится по строке с двумя числами $l$ и $r$ – ответы Шарика.

Выходные данные

Для каждого ответа Шарика выведите $»Yes»$, если он ответил правильно и $»No»$, если Шарик ошибся. Заметьте, что хотя в предыдущей задаче было необходимо найти минимальные числа $l$ и $r$, здесь Печкин проверять этого не будет.

Тесты

 Входные данные Выходные данные 5 1 2 4 3 1 5 1 4 1 5 2 3 5 1 1 1 4 1 3 1 5 5 5 2 4 Yes No Yes No

Код программы

Решение

Учитывая то, что максимум является ассоциативной операцией, для решения задачи
воспользуемся универсальным деревом отрезков.
Так как во входном потоке сперва идут требуемые результаты максимума на
отрезке, затем модификации отрезка и в конце отрезки, для которых необходимо
совпадение требуемого и реального максимума, то не обойтись без
запоминания/меморизации входных данных.
После этого задача упрощается, и для решения остаётся только пересматривать
все события, и сопоставлять требуемые резальтаты максимума на заданных
отрезках с реальными.

Ссылки
Код на ideone.com
Задача с сайта e-olymp.com.
Засчитанное решение.

# e-olymp 4496. Приключение Незнайки и его друзей

Задача с сайта e-olymp.com.

### Условие задачи

Все мы помним историю о том, как Незнайка со своими друзьями летали на воздушном шаре путешествовать. Но не все знают, что не все человечки влезли в шар, так как у него была ограниченная грузоподъемность.

В этой задаче Вам необходимо узнать, сколько же человечков улетело путешествовать. Известно, что посадка в шар не является оптимальной, а именно: человечки садятся в шар в той очереди, в которой они стоят, как только кому-то из них не хватает места, он и все оставшиеся в очереди разворачиваются и уходят домой.

### Входные данные

В первой строке содержится количество человечков $n (1 ≤ n ≤ { 10 }^{ 6 })$ в цветочном городе. Во второй строке заданы веса каждого из человечков в том порядке, в котором они будут садиться в шар. Все веса натуральные числа и не превышают ${ 10 }^{ 9 }$. Далее следует количество запросов $m (1 ≤ m ≤ { 10 }^{ 5 })$. Каждый запрос представляет собой одну строку. Если первое число в строке равно единице, то далее следует еще одно число $v (1 ≤ v ≤ { 10 }^{ 9 })$ – грузоподъемность воздушного шара. Если же оно равно двум, то далее следует два числа $x (1 ≤ x ≤ n)$ и $y (1 ≤ y ≤ { 10 }^{ 9 })$ — это значит, что вес человечка, стоящего на позиции $x$, теперь равен $y$.

### Выходные данные

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

### Тесты

 № Входные данные Выходные данные 1 5 1 2 3 4 5 5 1 7 1 3 2 1 5 1 7 1 3 3 2 2 0 2 2 1 2 3 1 4 2 1 10 1 4 2 0 3 2 999999999 1000000000 4 1 999999999 2 1 1000000000 1 999999999 1 1000000000 1 0 1

### Описание

В данной задаче требуется эффективно выполнять две операции: изменять значение одного из элементов массива и находить, сколько человечков поместится в шар при заданной грузоподъёмности. Это было реализовано при помощи структуры segment_tree. В функции main сначала вводится значение n и заполняется массив весов человечков weights, после чего по нему выполняется построение дерева отрезков tr. В его вершинах хранятся частичные суммы элементов массива. Да и в целом функции для построения и выполнения запроса модификации у него такие же, как и у обычного дерева отрезков для нахождения суммы на отрезке. Для удобства в массиве weights и в самом дереве используются элементы с первого по $n$-й, а не с нулевого по $\left( n-1 \right)$-й. Далее в ходе работы функции main в цикле выполняется обработка запросов. Сначала вводится тип запроса type. Если запрос второго типа, вводятся позиция человечка x, его новый вес y и вызывается метод update, пересчитывающий значения суммы в вершинах, на которые влияет это изменение. Иначе вводится грузоподъемность воздушного шара v и вызывается метод find_numb_of_p, который находит количество человечков, поместившихся в шар. Работает он следующим образом: если выполняется условие tree_l == tree_r, значит, рассматриваемый отрезок состоит из одного элемента, и функция возвращает $1$, если человечек может поместиться в шар, и $0$, если он слишком тяжёлый. Если отрезок больше, вычисляется индекс элемента, находящегося посередине tree_m. Далее, если сумма весов человечков в левом поддереве tree[v*2] больше, чем грузоподъёмность шара, то никто из правого поддерева уже не поместится, и искать следует только в левом поддереве. Иначе в шар следует посадить всех человечков из левого поддерева (их количество равно tree_m - tree_l + 1) и посмотреть, сколько поместится человечков из правого поддерева. При этом необходимо от максимально допустимого веса отнять вес человечков из левого поддерева, уже сидящих в шаре ( max_w-tree[v*2]).

Код на ideone.com. (C++)
Засчитанное решение на e-olymp.com. (C++)
Код на ideone.com. (Java)
Засчитанное решение на e-olymp.com. (Java)
При решении задачи был использован материал с сайта e-maxx.ru.

# Задача

В черный ящик кладутся листки с написанными на них числами. На каждом листке — ровно одно целое число. Иногда некоторые листки исчезают из ящика. После каждого события (когда в ящик положили листок, или когда из ящика исчез листок), нужно вывести число, которое встречается чаще всего на листках, находящихся в данный момент в ящике. Если таких чисел несколько, выведите наименьшее.

## Входные данные

Первая строка содержит количество событий $n$ $\left(1 \le n \le 2 \times 10^{5} \right)$. Каждая из следующих n строк содержит описание одного события:

• $+ x$ — положен листок с числом $x$ $\left(1 \le x \le 10^{6} \right)$;
• $- x$ — исчез листок с числом $x$ (гарантируется, что в ящике был хотя бы один листок с числом $x$).

## Выходные данные

Вывести в точности $n$ строк — по одной для каждого события. Каждая строка должна содержать одно число — ответ к задаче. Если после какого-то события ящик оказался пуст, следует вывести $0$.

# Тесты

Входные данные Выходные данные
3
+ 1
— 1
+ 2
1
0
2
6
+ 1
+ 1000000
— 1
+ 4
+ 4
— 1000000
1
1
1000000
4
4
4
8
+ 71
+ 91
+ 99
+ 71
— 71
— 91
— 71
— 99
71
71
71
71
71
71
99
0

# Решение задачи

Проанализируем задачу: так как требуется вывести число, которое встречается чаще всего на листках, находящихся в ящике после запроса удаления/добавления, а если таких чисел несколько, то вывести наименьшее, то задачу можно переформулировать следующим образом:

«Даётся последовательность (массив) объектов leaf $x_{1}$, $x_{2}$, $x_{3}$, $\ldots$, $x_{999999}$, $x_{1000000}$, представляющих из себя пару (number, amount)$=x_{i}=\left(i, a_{i}\right) \in {\mathbb{N}_{0}}^{2}$, где первые элементы пар $i$ представляет из себя число/номер листка, а вторые элементы $a_{i}$ — число листков с этим номером. Изначально все элементы пар $a_{i}$ равны нулю (так как изначально ящик пуст). Для запросов первого типа $+ x$ необходимо увеличивать на единицу число $a_{i}$ объекта, у которого номер $i$ равен $x$, а для запросов второго типа — уменьшать. Для каждого запроса необходимо вывести число $j$, удовлетворяющее условию $j = \min\limits_{i \in \mathbb{K}}{i}$, где $\mathbb{K} = \{i \mid a_{i} = \max\limits_{k \in \{1, 2, \ldots, 1000000\}}{a_{k}} \}$».

Иными словами, число $i$ соответствует некоторому элементу $x_{i} = \left(i, a_{i}\right)$, который в свою очередь определяется операцией такой, что $i$ и $a_{i}$ удовлетворяют приведённым выше условиям. Очевидно, что данная операция является ассоциативной (как объединение минимума и максимума на заданных множествах), а потому для решения задачи воспользуемся универсальным деревом отрезков.

Создадим дерево отрезков box методом read_and_construct из объектов leaf. Так как нумерация листков начинается с единицы, а их число не превышает $10^{6}$, зададим размер базы дерева отрезков $10^{6}+1$, добавив неё элемент с индексом $0$. Модифицируем метод read_and_construct таким образом, чтобы в функцию-препроцессор передавался номер элемента $i$, дабы была возможность задавать элементам $x_{i}$ их первоначальные значения $\left(i, 0\right)$. Вышеупомянутую операцию назовём max_leafs и определим таким образом, чтобы она принимала два аргумента $x_{i} = \left(i, a_{i}\right)$ и $x_{j} = \left(j, a_{j}\right)$ и возвращала тот из них, у которого значение $a$ является большим, а в случае равенства этих значений — аргумент с меньшим индексом. Нейтральным элементом относительно данной операции будет, очевидно, пара $\left(+\infty, 0\right)$, но в силу того, что номера элементов не превышают $10^6$, вместо неё мы будем пользоваться парой $\left(2 \times 10^{6}, 0\right)$.

Далее при запросах вида $+ x$ будем увеличивать соответствующее значение $a_{x}$ пары $\left(x, a_{x}\right)$ на единицу, а при запросах вида $- x$ — уменьшать. Для обоих запросов будем выводить номер заданного листка, который удовлетворяет приведённым в задаче условиям, с использованием метода result_on_segment на всём отрезке $\left[0, 10^{6}\right]$. Ответом для каждого запроса будет значение number пары, которую вернёт метод.

Примечание: ситуация когда ящик становится пустым нигде не обрабатывается, но в силу того, что мы определили массив на отрезке $\left[0, 10^{6}\right]$ вместо $\left[1, 10^{6}\right]$ в нём всегда есть пара $\left(0, 0\right)$ (листки с номером $0$, число (значение $b$) которых всегда равно $0$ в силу того, что листки с номером $0$ в ящик не добавляются). Так как определённая нами операция всегда возвращает минимальный номер листка, число которого максимально, то в случае, когда ящик пуст (т.е. значения всех $a_{i} = 0, i = 0, 1, \ldots, 10^{6}$) будет выводится номер листка $0$. Этот побочный эффект данного нами определения массива решает эту ситуацию и завершает решение задачи.

# Универсальное дерево отрезков

## Некоторые теоретические сведения

Обобщённое условие задач на дерево отрезков, как правило, выглядит так:
«Пусть дан моноид $\left(\mathbb{G}, \circ\right)$, где $\mathbb{G}$ — некоторое непустое множество, $\circ$ — ассоциативная бинарная алгебраическая операция на этом множестве, имеющая нейтральный элемент, $A$ — последовательность (массив) элементов из $\mathbb{G}$, содержащая $n$ элементов ($n \in \mathbb{N}$; с математической точки зрения $A$ — вектор, построенный из элементов $\mathbb{G}$, или $А = \left( x_{0}, x_{1}, \ldots, x_{n-1} \right) \in \mathbb{G}^{n}$).
Даётся $m$ ($m \in \mathbb{N}$) запросов двух типов:
1) вычислить значение выражения $x_{i} \circ x_{i+1} \circ \ldots \circ x_{j-1} \circ x_{j}$ с заданными $i$, $j$ ($0 \le i \le j \le n-1$, $i, j \in \mathbb{N} \cup \{ 0 \}$) и вывести его;
2) заменить значение элемента с индексом $k$ на $y$ ($k \in \mathbb{N} \cup \{ 0 \}$, $k \le n-1$, $y \in \mathbb{G}$).»

Как правило, человек, впервые увидевший задачу подобного рода, решает её следующим образом: для запросов первого типа (далее — запросы значения на отрезке $\left[i, j\right]$) создаётся вспомогательная переменная, изначально равная нейтральному элементу моноида (к примеру, если $\left( \mathbb{G}, \circ \right) = \left( \mathbb{Z}, + \right)$ то нейтральным элементом относительно $+$ является $0$), и запускается цикл на заданном отрезке, который «прибавляет» к ней новые «слагаемые», а обработка запросов из пункта 2 реализуется через простое присваивание элементу массива с заданным индексом $i$ значения $y$. Таким образом вычислительная сложность запросов замены составляет $O\left(1\right)$, а запросов поиска значения на отрезке $\left[i, j\right]$ в лучшем случае составляет $O\left(1\right)$, когда $i = j$, а в худшем $O\left(n\right)$, когда $i = 0$, $j = n-1$.

Дерево отрезковструктура данных, которая позволяет сбалансировать операции замены и вычисления значения на заданном отрезке до вычислительной сложности $O\left(\log_{2}{n}\right)$ и значительно улучшить общую сложность программы с $O\left(n+n\cdot m\right) = O\left(n\cdot m\right)$ до $O\left(n+m\cdot\log_{2}{n}\right)$.

Определение: массив/последовательность элементов/вектор, над которым построено дерево отрезков, называется базой дерева или просто базой, а число её элементов — её размерностью.

# Задача 1: единичная модификация

Написать класс «дерево отрезков», применимый к любой задаче на моноиде, в которой присутствуют запросы замены элемента и результата операции на отрезке,
и таблицу его базовых функций и параметров.

# Описание класса

Далее $n$ — размерность базы дерева.

Название объекта Описание
Параметр
TYPE Тип объектов дерева, над которыми будут проводится вычисления.
Внутренние объекты
SegmentTree Массив, хранящий в себе дерево отрезков.
base_capacity Переменная, хранящая округлённую к ближайшей большей степени двойки размерность базы дерева отрезков.
g Указатель на функцию, которая представляет из себя ассоциативную бинарную операцию. Формально определяется как функция/операция.
neutral Нейтральный элемент относительно бинарной операции g.
Методы класса
construct

Аргументы:

1. Адрес начала полуинтервала $a$;
2. Адрес конца полуинтервала $b$;
3. Ассоциативная бинарная операция f;
4. Нейтральный элемент относительно f.

Генерирует базу на основе полуинтервала $\left[a; b\right)$, копируя его элементы внутрь дерева, и строит на основе этой базы дерево отрезков.
Вычислительная сложность: $O\left(n\right)$.

1. Размер базы дерева;
2. Функция-препроцессор;
3. Ассоциативная бинарная операция f;
4. Нейтральный элемент относительно f.

Генерирует базу на основе элементов, возвращаемых функцией-препроцессором, и строит на их основе дерево отрезков.
Вычислительная сложность: $O\left(n\right)$.

assign Аргументы:

1. Индекс элемента;
2. Новое значение элемента.

Заменяет значение элемента с заданным индексом на новое.
Вычислительная сложность: $O\left(\log_{2}{n}\right)$.

result_on_segment Аргументы:

1. Индекс левого конца отрезка;
2. Индекс правого конца отрезка.

Возвращает результат функции на заданном отрезке.
Вычислительная сложность: $O\left(\log_{2}{n}\right)$.

# Инструкция по применению

Прежде всего, код универсального дерева отрезков необходимо скопировать в исходную программу.

Построение:

• Создать тип объектов (структуру данных), который будет использоваться в дереве для вычислений; (в зависимости от задачи. Вполне может быть, что необходимый для решения задачи класс уже создан. Например — int или double.)
• Инициализировать дерево отрезков, передав классу segments_tree в качестве параметра тип объектов, над которыми будут проводиться вычисления, и задав дереву имя. (инициализация класса segments_tree происходит аналогично инициализации класса vector)
• Построить дерево отрезков на основе заданных элементов при помощи метода construct или read_and_construct, передав методу соответствующие параметры (упомянутые в таблице выше);

Далее для вычисления результатов на отрезках и модификаций элементов с заданным индексом использовать методы result_on_segment и assign соответственно.

# Пример использования

Примечание: условие и альтернативное решение приведённой ниже задачи находится по этой ссылке.

### Решение задачи №4082 на www.e-olymp.com

Так как в задаче необходимо выводить знак или произведения на заданных отрезках (либо нуль), то очевидно, что сами числа не интересуют нас. Тогда каждое из них можно представить в виде пары (zero, plus)$= \left(a, b\right) \in \mathbb{B}^{2}$ (где $\mathbb{B}$ — булево множество), где первый элемент пар $a$ будет характеризовать равенство числа нулю, а $b$ — его положительность. Назовём структуру данных пар такого типа number_sign. Функция make_number_sign будет преобразовывать числа типа short в number_sign. Затем определим для этой структуры функцию умножения prod формулой prod(number_sign a, number_sign b)$=$ (a.zero|b.zero, !(a.plus^b.plus));. В первой части формулы используется дизъюнкция, так как произведение нуля и произвольного числа всегда должно возвращать нуль, а во второй части — эквиваленция, так как результат произведения является отрицательным, если оба аргумента различны по знаку.

Затем, предварительно считав размер базы, конструируем дерево отрезков методом read_and_construct, передавая ему число элементов базы, анонимную функцию-препроцессор, которая считывает элементы базы из входного потока и которая преобразует их в тип данных number_sign, функцию произведения prod и её нейтральный элемент number_sign(), являющийся парой $\left(0, 1\right)$, который по сути представляет из себя число $+1$ (нейтральный элемент умножения).

Остальная часть решения требует только замены старых элементов новыми и вычислений результатов на отрезках, для чего есть готовые методы класса.

# Задача 2

Дополнить класс «дерево отрезков» из первой задачи таким образом, чтобы для базы дерева были реализованы:

• параметры «вместимость» и «размер»;
• функции добавления нового элемента в базу;
• функции, возвращающие размер базы и вместимость дерева;
• функция изменения размера базы.

Написать таблицу новых функций и параметров.

# Описание дополнительных объектов класса

Название объекта Описание
Новый внутренний объект
base_size Переменная, хранящая размерность базы дерева отрезков.
Новые методы класса
begin

Аргументы: отсутствуют.
Возвращает адрес начала базы.
Вычислительная сложность: константа.

end Аргументы: отсутствуют.
Возвращает адрес конца базы.
Вычислительная сложность: константа.
push_back Аргумент: значение нового элемента базы.
Добавляет новый элемент в конец базы.
Вычислительная сложность: если база заполнена, то $O\left(n\right)$, иначе — $O\left(\log_{2}{n}\right)$.

pop_back

Аргументы: отсутствуют.
Удаляет элемент в конце базы.
Вычислительная сложность: $O\left(\log_{2}{n}\right)$.

insert

Аргументы:

1. Индекс нового элемента;
2. Значение нового элемента.

Добавляет на заданную позицию базы новый элемент с заданным значением.
Вычислительная сложность: $O\left(n\right)$.

erase

Аргумент: индекс удаляемого элемента.
Удаляет из базы элемент с заданным индексом.
Вычислительная сложность: $O\left(n\right)$.

size

Аргументы: отсутствуют.
Возвращает размерность базы дерева.
Вычислительная сложность: константа.

capacity

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

resize

Аргумент: новый размер базы.
Изменяет размер базы дерева, и преобразовывает незадействованные элементы в нейтральные
Вычислительная сложность: $O\left(n\right)$, если новый размер базы превысил вместимость дерева или является меньше, чем старый, и константа в противном случае.

# e-olymp 4481. В стране невыученных уроков

### Задача

Витя попал в страну невыученных уроков. Для того, чтобы вернуться домой ему нужно выполнить множество заданий. В этой задаче он должен выиграть у стражей в НОД-игру. Правила этой игры очень простые: есть массив натуральных чисел, после чего игроки выбирают два числа $l$ и $r$, и им надо посчитать наибольший общий делитель (НОД) всех элементов в массиве с индексами от $l$ до $r$ включительно. Кто быстрее посчитает, тот и выиграл. Чтобы избежать нечестных игр, они иногда заменяют некоторые числа в массиве на другие.

Витя очень хочет домой, помогите ему в этом, для чего напишите программу, которая будет очень быстро считать НОД на заданном промежутке.

#### Входные данные

Первая строка содержит количество элементов $n$ $(1\leq n\leq 10^5)$ в массиве. Во второй строке находится $n$ чисел – элементы $a_i$ $(1\leq a_i\leq 10^9)$ массива. В третьей строке находится количество запросов $m$ $(1\leq m\leq 10^5)$. Далее в $m$ строках находятся по три числа $q$, $l$, $r$ $(1\leq l\leq r\leq n)$. Если $q=1$, требуется посчитать НОД элементов на промежутке $[l,r]$, если $q=2$, то надо заменить элемент в позиции $l$ на число $r$.

#### Выходные данные

Для каждого запроса с номером $l$ в отдельной строке выведите ответ на запрос.

#### Тесты

 Входные данные: Выходные данные: 5 2 4 6 10 8 6 1 1 5 1 2 3 2 5 15 2 3 10 1 3 5 1 1 5 2 2 5 1

#### Алгоритм решения

Данная задача решена с помощью структуры данных «дерево отрезков». В каждой вершине дерева храним НОД всех чисел на соответствующем отрезке массива. Функции, отвечающие за построение самого дерева отрезков, нахождение  НОД на отрезке и запрос на модификацию элемента являются рекурсивными.  Дерево строим следующим образом: листьями данного дерева будут сами элементы исходного массива, а значения элементов, находящихся на уровень выше, будут представлять собой НОД двух соседних листов. Таким же образом считаем значения вершин следующего уровня и т.д. Чтобы найти НОД на заданном отрезке рассматриваем случаи расположения данного отрезка. Он может полностью принадлежать одному потомку, а может быть разбит между правым и левым потомками. В первом случае функцию запускаем от одного потомка и получаем требуемое, во втором случае функцию запускаем от двух потомков и находим от полученных результатов НОД. При выполнении запроса на модификацию запускаем функцию от корня, спускаемся до требуемого элемента, изменяем его, и поднимаемся обратно к корню, модифицируя значения вершин, для которых данный элемент является подотрезком.

В самой задаче, в зависимости от требуемого, в цикле находим НОД на заданном отрезке или выполняем модификацию элемента.

Для получения подробной информации о структуре данных «Дерево отрезков» можно перейти по данной ссылке
Ссылка на засчитанное решение на e-olymp
Ссылка на условие задачи
Ссылка на решение задачи на ideone.com