import java.util.*; public class SegmentTree2 { // 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 n; 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 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 root, int left, int right) { int mid = (left + right) >> 1; value[(2 * root + 1)] = joinValueWithDelta(value[(2 * root + 1)], deltaEffectOnSegment(delta[root], mid - left + 1)); value[(2 * root + 2)] = joinValueWithDelta(value[(2 * root + 2)], deltaEffectOnSegment(delta[root], right - mid)); delta[(2 * root + 1)] = joinDeltas(delta[(2 * root + 1)], delta[root]); delta[(2 * root + 2)] = joinDeltas(delta[(2 * root + 2)], delta[root]); delta[root] = getNeutralDelta(); } public SegmentTree2(int n) { this.n = n; value = new int[4 * n]; delta = new int[4 * n]; init(0, 0, n - 1); } void init(int root, int left, int right) { if (left == right) { value[root] = getInitValue(); delta[root] = getNeutralDelta(); } else { init(2 * root + 1, left, (left + right) / 2); init(2 * root + 2, (left + right) / 2 + 1, right); value[root] = queryOperation(value[2 * root + 1], value[2 * root + 2]); delta[root] = getNeutralDelta(); } } public int query(int from, int to) { return query(from, to, 0, 0, n - 1); } int query(int from, int to, int root, int left, int right) { if (from == left && to == right) return value[root]; pushDelta(root, left, right); int mid = (left + right) >> 1; if (from <= mid && to > mid) return queryOperation( query(from, Math.min(to, mid), root * 2 + 1, left, mid), query(Math.max(from, mid + 1), to, root * 2 + 2, mid + 1, right)); else if (from <= mid) return query(from, Math.min(to, mid), root * 2 + 1, left, mid); else if (to > mid) return query(Math.max(from, mid + 1), to, root * 2 + 2, mid + 1, right); else throw new RuntimeException("Incorrect query from " + from + " to " + to); } public void modify(int from, int to, int delta) { modify(from, to, delta, 0, 0, n - 1); } void modify(int from, int to, int delta, int root, int left, int right) { if (from == left && to == right) { value[root] = joinValueWithDelta(value[root], deltaEffectOnSegment(delta, right - left + 1)); this.delta[root] = joinDeltas(this.delta[root], delta); return; } pushDelta(root, left, right); int mid = (left + right) >> 1; if (from <= mid) modify(from, Math.min(to, mid), delta, 2 * root + 1, left, mid); if (to > mid) modify(Math.max(from, mid + 1), to, delta, 2 * root + 2, mid + 1, right); value[root] = queryOperation(value[2 * root + 1], value[2 * root + 2]); } // Random test public static void main(String[] args) { Random rnd = new Random(1); for (int step = 0; step < 1000; step++) { int n = rnd.nextInt(50) + 1; int[] x = new int[n]; SegmentTree2 t = new SegmentTree2(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"); } }