Побудуємо дерево відрізків на діапазоні і спочатку обнулимо його. Нехай торговець продавав шапки в населених пунктах [l_i; r_i], починаючи з ціни p_i. Розіб'ємо відрізок [l_i; r_i] на фундаментальні відрізки [lx_1; ry_1], [lx_2; ry_2], ..., [lx_k; ry_k]. Тоді у вершину, що відповідає відрізку [lx_q; ry_q]~(1 \le q \le k), заносимо число
Наприклад, нехай n = 5, і перша торгівля охоплює міста з номерами від до , починаючи з ціни . Тоді відрізок розпадеться на фундаментальні: [2; 2], [3; 3], [4; 5]. Після обробки першої операції дерево відрізків буде виглядати наступним чином:
Якщо фундаментальний відрізок містить значення , це означає, що:
торговець продавав шапки у всіх містах від до .
в місті шапка продавалася за ціною , у місті a + 1 за ціною p + 1, і так далі, аж до міста , де її ціна складала p + b - a.
Розглянемо процедуру обробки запиту [left; right] (відрізка, на якому торговець веде торгівлю) на діапазоні [lpos; rpos], якщо початкова ціна шапки становить .
В лівому підвідрізку торговець буде продавати шапки в len = min(mid, right) - left + 1 містах, починаючи з ціни . В правому підвідрізку перша ціна шапки в місті, куди прийде торговець, становитиме x + len. Таким чином, на відрізку з номерами [max(left, mid + 1), right] торгівля почнеться з ціни x + len. Однак якщо len < 0 (що можливо, якщо весь відрізок запиту знаходиться в правому підвідрізку), слід покласти len = 0.
Розглянемо відрізок , у якого є два підвідрізки: і [m + 1; b]. Якщо в місті торговець продав шапку за ціною , то в місті m + 1 її ціна становитиме p + m + 1 - a.
Під час обробки запитів реалізуємо проталкивання значень, що підтримує максимум.
Для виводу відповіді слід пройти по дереву, протиснути всі значення до листя і вивести їх.
Приклад
Розглянемо виконання двох запитів, наведених у прикладі. Розіб'ємо відрізки запитів на фундаментальні:
[1; 3] = [1; 3];
[2; 4] = [2; 2] + [3; 3] + [4; 4].
Реалізація алгоритму
Оголосимо масив SegTree для зберігання дерева відрізків.
#define MAX 300010
long long SegTree[4*MAX];Функція Push виконує проталкивання значення з вершини в її нащадків.
void Push(int v, int lpos, int mid, int rpos)
{
if (SegTree[v])
{
SegTree[2 * v] = max(SegTree[2 * v], SegTree[v]);
SegTree[2 * v + 1] = max(SegTree[2 * v + 1],
SegTree[v] + mid - lpos + 1);
SegTree[v] = 0;
}
}Функція Update виконує продаж шапок на проміжку [left; right], починаючи з ціни .
void Update(int v, int lpos, int rpos, int left, int right,
long long x)
{
if (left > right) return;
if ((lpos == left) && (rpos == right))
SegTree[v] = max(SegTree[v], x);
else
{
int mid = (lpos + rpos) / 2;
Push(v, lpos, mid, rpos);
int len = min(mid, right) - left + 1;
if (len < 0) len = 0;
Update(2 * v, lpos, mid, left, min(mid, right), x);
Update(2 * v + 1, mid + 1, rpos, max(left, mid + 1),
right, x + len);
}
}Функція PrintResult проталкиває значення з внутрішніх вершин до листків і виводить підсумковий стан масиву.
void PrintResult(int v, int lpos, int rpos)
{
if (lpos == rpos)
printf("%lld ", SegTree[v]);
else
{
int mid = (lpos + rpos) / 2;
Push(v, lpos, mid, rpos);
PrintResult(2 * v, lpos, mid);
PrintResult(2 * v + 1, mid + 1, rpos);
}
}Основна частина програми. Читаємо вхідні дані.
scanf("%d %d", &n, &m);
memset(SegTree,0,sizeof(SegTree));Обробляємо запитів.
for(i = 0; i < m; i++)
{
scanf("%d %d %lld", &l, &r, &x);
Update(1,1,n,l,r,x);
}Виводимо результат.
PrintResult(1,1,n);
printf("\n");