Мне нужно написать программу, которая эффективно находит длину самой длинной непрерывной последовательности нулей в заданном сегменте [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, но я ее не вижу...




Ваш метод 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);
}
В чем смысл prefSeq, suffSeq и rmq?