Uşaq [l; r] seqmentindəki iki sərnişini yalnız və yalnız bu seqmentdəki heyvanların kütlələrindən ən kiçik ikisinin cəmi -dan artıq olmadıqda seçə bilər. Həqiqətən, əgər hər hansı bir heyvan cütü uyğun gəlirsə, onda ən yüngül iki heyvanın cütü daha çox uyğun gələcək.
Buna görə də, hər təpəsində öz seqmentindəki iki minimumu saxlayan bir seqment ağacı qurmaq olar. Lakin bizi minimumların özləri yox, yalnız cəmi -dan artıq olmayan iki ədədin mövcud olub-olmaması maraqlandırır. Bu, hər təpədə yalnız bir ədəd saxlamağa imkan verir.
Təpələrdəki dəyərlər. Seqment ağacının yarpaqları heyvanların kütlələrini saxlayır. Hər daxili təpə aşağıdakıları saxlayır:
əgər onun seqmentində ümumi kütləsi -dan artıq olmayan iki heyvan varsa, ;
əks halda, onun seqmentindəki heyvanın minimum kütləsini.
Heyvanların kütlələri müsbətdir, ona görə dəyəri heç bir kütlə ilə üst-üstə düşmür və birmənalı şəkildə uyğun cütün tapıldığını bildirir.
Uşaqların birləşdirilməsi. Təpənin dəyəri onun uşaqlarının və dəyərlərindən hesablanır. Təpənin seqmentindəki uyğun heyvan cütü ya tamamilə onun yarılarından birində yerləşir, ya da sol yarıdan bir heyvandan və sağ yarıdan bir heyvandan ibarətdir. Ona görə:
əgər x = 0 və ya y = 0 olarsa, uyğun cüt yarılardan birində yerləşir, və təpənin dəyəri -dır;
əks halda, və yarılardakı minimum kütlələrdir, və müxtəlif yarılardan olan heyvanların ən yaxşı cütünün ümumi kütləsi x + y-dir. Əgər x + y \le k olarsa, təpənin dəyəri -dır, əks halda \min(x, y)-dir.
Belə bir birləşdirmə funksiyası ilə məsələ nöqtəvi yeniləmələrlə standart seqment ağacı vasitəsilə həll olunur.
tipli sorğu üçün, əgər [l; r] seqmentindəki dəyər -a bərabərdirsə, cavab "Yes"-dir, əks halda "No"-dur.
Nümunə
Nümunədəki sorğulara baxaq, k = 9. Başlanğıcda heyvanların kütlələri 1, 3, 1, 6, 6, 7-dir:
: ən yüngül iki heyvanın kütləsi və -dir, 1 + 1 = 2 \le 9, cavab "Yes"-dir;
: 1 + 3 = 4 \le 9, cavab "Yes"-dir;
: dördüncü heyvanın kütləsi olur;
: 7 + 6 = 13 > 9, cavab "No"-dur;
: 6 + 7 = 13 > 9, cavab "No"-dur;
və : birinci və üçüncü heyvanların kütlələri və olur.
Son sorğusundan əvvəl heyvanların kütlələri 7, 3, 8, 7, 6, 7-dir. Onlar üçün seqment ağacı aşağıda göstərilmişdir. Hər təpədə onun seqmenti və saxlanılan dəyər göstərilir. Yarpaqlar sarı rənglə, dəyəri olan təpə isə narıncı rənglə vurğulanmışdır.
Daxili təpələrdəki dəyərləri hesablayaq:
: 7 + 3 = 10 > 9, dəyər \min(7, 3) = 3-dür;
: 3 + 8 = 11 > 9, dəyər \min(3, 8) = 3-dür;
: 7 + 6 = 13 > 9, dəyər \min(7, 6) = 6-dır;
: 6 + 7 = 13 > 9, dəyər \min(6, 7) = 6-dır;
: 3 + 6 = 9 \le 9, dəyər -dır.
Yalnız təpəsi saxlayır: kütlələri və olan ən yüngül iki heyvan seqmentin müxtəlif yarılarındadır, və onların ümumi kütləsi -dur. Beləliklə, son sorğunun cavabı "Yes"-dir.
Alqoritmin tətbiqi
Sabitləri və işçi massivləri elan edək. SegTree massivi seqment ağacını saxlayır, heyvanların kütlələri isə massivində saxlanılır. sabiti hər hansı bir heyvanın kütləsindən böyükdür və boş seqment üçün neytral element kimi istifadə olunur. ilə istənilən kütlənin cəmi 2 \cdot 10^9 + 10-dan artıq olmur və tipinə sığır.
#define MAX 1000001
#define INF 1000000010
int SegTree[4 * MAX];
int a[MAX];f funksiyası uşaqların və dəyərlərini birləşdirir. Əgər uşaqlardan ən azı birində varsa, onda onun seqmentində artıq uyğun iki sərnişin var. Əgər x + y \le k olarsa, sol və sağ yarıların ən yüngül heyvanları uyğun cüt təşkil edir. Hər iki halda qaytarın; əks halda və -nin minimumunu qaytarın.
int f(int x, int y)
{
if (x == 0 || y == 0 || x + y <= k) return 0;
return min(x, y);
}BuildTree funksiyası massivindən seqment ağacını qurur. təpəsi [lpos; rpos] seqmentinə uyğun gəlir. Yarpaqlar heyvanların kütlələrini saxlayır, daxili təpələrdəki dəyərlər isə funksiyası ilə hesablanır.
void BuildTree(int v, int lpos, int rpos)
{
if (lpos == rpos)
SegTree[v] = a[lpos];
else
{
int mid = (lpos + rpos) / 2;
BuildTree(2 * v, lpos, mid);
BuildTree(2 * v + 1, mid + 1, rpos);
SegTree[v] = f(SegTree[2 * v], SegTree[2 * v + 1]);
}
}Query funksiyası [left; right] seqmentindəki dəyəri qaytarır: əgər onda ümumi kütləsi -dan artıq olmayan iki sərnişin varsa , əks halda heyvanın minimum kütləsini. təpəsi [lpos; rpos] seqmentinə uyğun gəlir. Boş seqment üçün neytral dəyəri qaytarılır.
int Query(int v, int lpos, int rpos, int left, int right)
{
if (left > right) return INF;
if ((lpos == left) && (rpos == right)) return SegTree[v];
int mid = (lpos + rpos) / 2;
return f(Query(2 * v, lpos, mid, left, min(right, mid)),
Query(2 * v + 1, mid + 1, rpos, max(left, mid + 1), right));
}Update funksiyası indeksli elementə dəyərini mənimsədir və yarpaqdan köyə qədər olan yol üzərindəki bütün təpələrdəki dəyərləri yenidən hesablayır. təpəsi [lpos; rpos] seqmentinə uyğun gəlir.
void Update(int v, int lpos, int rpos, int pos, int val)
{
if (lpos == rpos)
SegTree[v] = val;
else
{
int mid = (lpos + rpos) / 2;
if (pos <= mid) Update(2 * v, lpos, mid, pos, val);
else Update(2 * v + 1, mid + 1, rpos, pos, val);
SegTree[v] = f(SegTree[2 * v], SegTree[2 * v + 1]);
}
}Proqramın əsas hissəsi. Heyvanların sayı -i və qalan tutumu -nı oxuyun. Heyvanların kütlələrini indeksindən başlayaraq massivinə oxuyun.
scanf("%d %d", &n, &k);
for (i = 1; i <= n; i++)
scanf("%d", &a[i]);a[1 \ldots n] massivinin elementlərindən seqment ağacını qurun.
BuildTree(1, 1, n);sorğusunu bir-bir emal edin. Heyvanlar -dən başlayaraq nömrələnir, massivinin elementləri də indeksindən başlayaraq saxlanılır, ona görə sorğulardan olan indekslər dəyişiklik olmadan istifadə olunur.
scanf("%d", &q);
for (j = 0; j < q; j++)
{
scanf("%d %d %d", &t, &l, &r);tipli sorğu: [l; r] seqmentindəki dəyəri hesablayın. Əgər o -a bərabərdirsə, iki sərnişin tapılıb.
if (t == 1)
{
int Res = Query(1, 1, n, l, r);
if (Res == 0) printf("Yes\n"); else printf("No\n");
}tipli sorğu: indeksli heyvana kütləsini mənimsədin.
else
Update(1, 1, n, l, r);
}