164 lines
4.5 KiB
Java
164 lines
4.5 KiB
Java
import java.util.*;
|
|
|
|
public class SegmentTreeFast2 {
|
|
|
|
// Modify the following 5 methods to implement your custom operations on the tree.
|
|
// This example implements Add/Max operations. Operations like Add/Sum, Set/Max can also be implemented.
|
|
int modifyOperation(int x, int y) {
|
|
return x + y;
|
|
}
|
|
|
|
// query (or combine) operation
|
|
int queryOperation(int leftValue, int rightValue) {
|
|
return Math.max(leftValue, rightValue);
|
|
}
|
|
|
|
int deltaEffectOnSegment(int delta, int segmentLength) {
|
|
if (delta == getNeutralDelta()) return getNeutralDelta();
|
|
// Here you must write a fast equivalent of following slow code:
|
|
// int result = delta;
|
|
// for (int i = 1; i < segmentLength; i++) result = queryOperation(result, delta);
|
|
// return result;
|
|
return delta;
|
|
}
|
|
|
|
int getNeutralDelta() {
|
|
return 0;
|
|
}
|
|
|
|
int getInitValue() {
|
|
return 0;
|
|
}
|
|
|
|
// generic code
|
|
int[] value;
|
|
int[] delta; // delta[i] affects value[2*i+1], value[2*i+2], delta[2*i+1] and delta[2*i+2]
|
|
int[] len;
|
|
|
|
int joinValueWithDelta(int value, int delta) {
|
|
if (delta == getNeutralDelta()) return value;
|
|
return modifyOperation(value, delta);
|
|
}
|
|
|
|
int joinDeltas(int delta1, int delta2) {
|
|
if (delta1 == getNeutralDelta()) return delta2;
|
|
if (delta2 == getNeutralDelta()) return delta1;
|
|
return modifyOperation(delta1, delta2);
|
|
}
|
|
|
|
void pushDelta(int i) {
|
|
int d = 0;
|
|
for (; (i >> d) > 0; d++)
|
|
;
|
|
for (d -= 2; d >= 0; d--) {
|
|
int x = i >> d;
|
|
value[x] = joinValueWithDelta(value[x], deltaEffectOnSegment(delta[x >> 1], len[x]));
|
|
value[(x ^ 1)] = joinValueWithDelta(value[(x ^ 1)], deltaEffectOnSegment(delta[x >> 1], len[(x ^ 1)]));
|
|
delta[x] = joinDeltas(this.delta[x], delta[x >> 1]);
|
|
delta[(x ^ 1)] = joinDeltas(this.delta[(x ^ 1)], delta[x >> 1]);
|
|
delta[x >> 1] = getNeutralDelta();
|
|
}
|
|
}
|
|
|
|
public SegmentTreeFast2(int n) {
|
|
value = new int[2 * n];
|
|
for (int i = 0; i < n; i++)
|
|
value[i + n] = getInitValue();
|
|
for (int i = 2 * n - 1; i > 1; i -= 2)
|
|
value[i >> 1] = queryOperation(value[i], value[i ^ 1]);
|
|
|
|
delta = new int[2 * n];
|
|
Arrays.fill(delta, getNeutralDelta());
|
|
|
|
len = new int[2 * n];
|
|
Arrays.fill(len, n, 2 * n, 1);
|
|
for (int i = 2 * n - 1; i > 1; i -= 2)
|
|
len[i >> 1] = len[i] + len[i ^ 1];
|
|
}
|
|
|
|
public int query(int from, int to) {
|
|
from += value.length >> 1;
|
|
to += value.length >> 1;
|
|
pushDelta(from);
|
|
pushDelta(to);
|
|
int res = 0;
|
|
boolean found = false;
|
|
for (; from <= to; from = (from + 1) >> 1, to = (to - 1) >> 1) {
|
|
if ((from & 1) != 0) {
|
|
res = found ? queryOperation(res, value[from]) : value[from];
|
|
found = true;
|
|
}
|
|
if ((to & 1) == 0) {
|
|
res = found ? queryOperation(res, value[to]) : value[to];
|
|
found = true;
|
|
}
|
|
}
|
|
if (!found)
|
|
throw new RuntimeException();
|
|
return res;
|
|
}
|
|
|
|
public void modify(int from, int to, int delta) {
|
|
from += value.length >> 1;
|
|
to += value.length >> 1;
|
|
pushDelta(from);
|
|
pushDelta(to);
|
|
int ta = -1;
|
|
int tb = -1;
|
|
for (; from <= to; from = (from + 1) >> 1, to = (to - 1) >> 1) {
|
|
if ((from & 1) != 0) {
|
|
value[from] = joinValueWithDelta(value[from], deltaEffectOnSegment(delta, len[from]));
|
|
this.delta[from] = joinDeltas(this.delta[from], delta);
|
|
if (ta == -1)
|
|
ta = from;
|
|
}
|
|
if ((to & 1) == 0) {
|
|
value[to] = joinValueWithDelta(value[to], deltaEffectOnSegment(delta, len[to]));
|
|
this.delta[to] = joinDeltas(this.delta[to], delta);
|
|
if (tb == -1)
|
|
tb = to;
|
|
}
|
|
}
|
|
for (int i = ta; i > 1; i >>= 1)
|
|
value[i >> 1] = queryOperation(value[i], value[i ^ 1]);
|
|
for (int i = tb; i > 1; i >>= 1)
|
|
value[i >> 1] = queryOperation(value[i], value[i ^ 1]);
|
|
}
|
|
|
|
// Random test
|
|
public static void main(String[] args) {
|
|
Random rnd = new Random();
|
|
for (int step = 0; step < 1000; step++) {
|
|
int n = rnd.nextInt(50) + 1;
|
|
int[] x = new int[n];
|
|
SegmentTreeFast2 t = new SegmentTreeFast2(n);
|
|
Arrays.fill(x, t.getInitValue());
|
|
for (int i = 0; i < 1000; i++) {
|
|
int b = rnd.nextInt(n);
|
|
int a = rnd.nextInt(b + 1);
|
|
int cmd = rnd.nextInt(3);
|
|
if (cmd == 0) {
|
|
int delta = rnd.nextInt(100) - 50;
|
|
t.modify(a, b, delta);
|
|
for (int j = a; j <= b; j++)
|
|
x[j] = t.joinValueWithDelta(x[j], delta);
|
|
} else if (cmd == 1) {
|
|
int res1 = t.query(a, b);
|
|
int res2 = x[a];
|
|
for (int j = a + 1; j <= b; j++)
|
|
res2 = t.queryOperation(res2, x[j]);
|
|
if (res1 != res2)
|
|
throw new RuntimeException();
|
|
|
|
} else {
|
|
for (int j = 0; j < n; j++) {
|
|
if (t.query(j, j) != x[j])
|
|
throw new RuntimeException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
System.out.println("Test passed");
|
|
}
|
|
}
|