Проблема с задачей дерева сегментов

Мне нужно написать программу, которая эффективно находит длину самой длинной непрерывной последовательности нулей в заданном сегменте [l, r] (определенном подмассиве) и обновляет значение по запросу, причем обе операции выполняются за логарифмическое время.

У меня есть этот код:

import java.io.*;
import java.util.Objects;
import java.util.StringTokenizer;

public class task {
    static class treeLeaf {
        int maxSeq;
        int prefSeq;
        int suffSeq;
        int length;

        treeLeaf(int maxSeq, int prefSeq, int suffSeq, int length) {
            this.maxSeq = maxSeq;
            this.prefSeq = prefSeq;
            this.suffSeq = suffSeq;
            this.length = length;
        }
    }

    static treeLeaf merge(treeLeaf left, treeLeaf right) {
        int maxSeq = Math.max(left.maxSeq, right.maxSeq);
        if (left.suffSeq > 0 && right.prefSeq > 0) {
            maxSeq = Math.max(maxSeq, left.suffSeq + right.prefSeq);
        }

        int prefSeq = left.prefSeq;
        if (left.prefSeq == left.length) {
            prefSeq += right.prefSeq;
        }

        int suffSeq = right.suffSeq;
        if (right.suffSeq == right.length) {
            suffSeq += left.suffSeq;
        }

        return new treeLeaf(maxSeq, prefSeq, suffSeq, left.length + right.length);
    }

    static treeLeaf rmq(int l, int r, treeLeaf[] tree) {
        int n = tree.length / 2;
        l += n;
        r += n;
        treeLeaf res = new treeLeaf(0, 0, 0, 0);

        while (l <= r) {
            if ((l & 1) == 1) {
                res = merge(res, tree[l]);
                l++;
            }
            if ((r & 1) == 0) {
                res = merge(res, tree[r]);
                r--;
            }
            if (l > r) break;
            l /= 2;
            r /= 2;
        }
        return res;
    }
}

Но когда я запускаю тест:

18
6 0 0 1 0 0 0 0 2 4 5 6 9 0 0 0 0 1
1
QUERY 1 18

Моя программа печатает 5 вместо 4. Я подозреваю, что проблема в функции merge, но я ее не вижу...

В чем смысл prefSeq, suffSeq и rmq?

dragoness 18.05.2024 23:05
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
1
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

static treeLeaf rmq(int l, int r, treeLeaf[] tree) {
    int n = tree.length / 2;
    treeLeaf leftRes = new treeLeaf(0, 0, 0, 0), rightRes = new treeLeaf(0, 0, 0, 0);
    for (l += n, r += n; l <= r; l /= 2, r /= 2) {
        if ((l & 1) == 1) leftRes = merge(leftRes, tree[l++]);
        if ((r & 1) == 0) rightRes = merge(tree[r--], rightRes);
    }
    return merge(leftRes, rightRes);
}

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