Как получить первое значение больше x в диапазоне с деревом сегментов

Я пытаюсь использовать дерево сегментов для обработки запросов (в O(log N) на каждый запрос) формы: найти первое значение > x в определенном диапазоне [ql, qr] (массива размером N).

Я использовал рекурсивный метод для создания дерева сегментов и его обновления, но мне не удалось получить индекс first value > x в моем диапазоне.

Вот моя реализация, которая сейчас не работает:

#include <utility>
#include <iostream>
#include <vector>
using namespace std;

vector<int> seg;
vector<int> torre;
int sizeN;

//recursive build of the segtree
long long int build(int i, int l, int r, vector<int> &torri) {

    if (r-l==1) return seg[i] = torri[l]; //base case

    int mid = (l+r)/2; //split in half
    seg[i] = max(build(2*i, l, mid, torri), build((2*i)+1, mid, r, torri));

    //return the value of the segment
    return seg[i];
}

//recursive update of the segtree
void update(int i, int l, int r, int pos, long long int val) {

    if (r-l==1) { seg[i] = val; return; } //base case

    int mid = (l+r)/2; //find the middle
    if (pos<mid) update(2*i, l, mid, pos, val); //left half
    else update(2*i+1, mid, r, pos, val); //right half

    seg[i] = max(seg[2*i],seg[2*i+1]); //update with the max
}

int query_destra (int i, int l, int r, int ql, int qr, int x) {

    //base case
    if (ql >= r or qr <= l) return -1;//no intersection

    if (l >= ql and r <= qr) { //included
        if (seg[i] <= x) return -1; //if ... the node is not interesting

        //return i; <----------- IM MISSING SOMETHING HERE TO MAKE IT RETURN I CORRECTLY
    }

    int mid = (l+r)/2; //find the center

    //prioritizes the first value, if its not interesting, go to the second
    int ans = query_destra(2*i, l, mid, ql, qr, x);
    if (ans != -1) return ans;
    return query_destra(2*i+1, mid, r, ql, qr, x);
}

pair<int, int> chiedi(int x) {
    return make_pair(0 /*query_sinistra(1,0,sizeN, 0, x, torre[x])*/,query_destra(1, 0, sizeN, x, sizeN, torre[x]));
}

void cambia(int x, int h) {
    update(1, 0, sizeN, x, h);
}

void inizializza(int N, vector<int> H) {
    sizeN = H.size();
    torre.resize(sizeN);
    seg.resize(sizeN*4);
    for(int i=0; i<sizeN; i++) torre[i] = H[i];
    build(1,0,N,H);
}

int main() {
    vector vec{6, 4, 2, 0, 8, 4};
    inizializza(vec.size(), vec);
    cout << query_destra(1, 0, sizeN, 1, 5, 4) << '\n'; 
    // should produce 4, the index of the first value larger than 4 in the subarray from index 1 to 5 (exclusive), but gives -1
}

Мне удалось получить самое высокое значение в диапазоне, но не первое, поэтому я попробовал другой подход: я попробовал просто поставить «return i» внутри включенных случаев, но, судя по результатам, это было ОЧЕНЬ неправильно, и не установка где-нибудь «return i» просто возвращает -1 каждый раз.

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

Пример того, каким должен быть результат: при начальном массиве [6, 4, 2, 0, 8, 4], x = 4 и моем диапазоне от позиции 1 до позиции 5 моя программа должна иметь возможность возвращать 4 (позиция 8, первое число выше, чем стартовый). Мне нужно сделать это для числа в массиве как вперед, так и назад. Я использую С++17. Любая помощь приветствуется, заранее спасибо.

«весь мой код» — требуется редко. Пожалуйста, предоставьте минимально воспроизводимый пример, где вы проделали тяжелую работу по исключению ненужных частей из материала, который мы, пытаясь помочь вам, должны проанализировать.

Ted Lyngmo 29.06.2024 03:39

Я упростил ваш пример, чтобы более наглядно продемонстрировать проблему.

Unmitigated 29.06.2024 07:42
int mid = (l+r)/2; //find the middle -- Возможно переполнение, если l + r превышает максимальное значение int. Вместо этого используйте std::midpoint.
PaulMcKenzie 29.06.2024 14:00

@PaulMcKenzie Забыл упомянуть об этом в основном сообщении, я использую C++17, и эта функция была создана для C++20 или выше.

Tizio 29.06.2024 15:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваше решение почти правильное; вы просто упускаете момент, когда вам следует вернуть фактический индекс. Когда вы сузили поиск до конечного узла при спуске по дереву, вы можете напрямую вернуть левый индекс.

Замените эти строки

if (l >= ql and r <= qr) {
    if (seg[i] <= x) return -1;

    //return i;
}

с

if (seg[i] <= x) return -1;
if (r == l + 1) return l;

Я не думаю, что понимаю это решение. Я попытался поместить ваше решение в свой код, и оно находит, казалось бы, случайное число с различными примерами. Я попробовал этот пример: v[1, 3, 6, 8, 8, 9, 10] и x=1, поэтому теперь программа должна найти первый элемент справа выше torre[1] = 3, но по какой-то причине возвращает 5 (9). Если вместо другого вектора вектор v[1, 7, 6, 8, 8, 9, 10] и x=1, он должен вернуть 3 (позиция первых 8), но вместо этого он снова возвращает 5 (позиция 9).

Tizio 29.06.2024 14:56

@Tizio Я забыл, что вы использовали исключительное право для своих узлов. Измените строку на if (r == l + 1) return l;

Unmitigated 29.06.2024 16:13

Другие вопросы по теме