package class36; // 来自美团 // 给定一个数组arr,长度为N,做出一个结构,可以高效的做如下的查询 // 1) int querySum(L,R) : 查询arr[L...R]上的累加和 // 2) int queryAim(L,R) : 查询arr[L...R]上的目标值,目标值定义如下: // 假设arr[L...R]上的值为[a,b,c,d],a+b+c+d = s // 目标值为 : (s-a)^2 + (s-b)^2 + (s-c)^2 + (s-d)^2 // 3) int queryMax(L,R) : 查询arr[L...R]上的最大值 // 要求: // 1) 初始化该结构的时间复杂度不能超过O(N*logN) // 2) 三个查询的时间复杂度不能超过O(logN) // 3) 查询时,认为arr的下标从1开始,比如 : // arr = [ 1, 1, 2, 3 ]; // querySum(1, 3) -> 4 // queryAim(2, 4) -> 50 // queryMax(1, 4) -> 3 public class Code05_Query3Problems { public static class SegmentTree { private int[] max; private int[] change; private boolean[] update; public SegmentTree(int N) { max = new int[N << 2]; change = new int[N << 2]; update = new boolean[N << 2]; for (int i = 0; i < max.length; i++) { max[i] = Integer.MIN_VALUE; } } private void pushUp(int rt) { max[rt] = Math.max(max[rt << 1], max[rt << 1 | 1]); } // ln表示左子树元素结点个数,rn表示右子树结点个数 private void pushDown(int rt, int ln, int rn) { if (update[rt]) { update[rt << 1] = true; update[rt << 1 | 1] = true; change[rt << 1] = change[rt]; change[rt << 1 | 1] = change[rt]; max[rt << 1] = change[rt]; max[rt << 1 | 1] = change[rt]; update[rt] = false; } } public void update(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { update[rt] = true; change[rt] = C; max[rt] = C; return; } int mid = (l + r) >> 1; pushDown(rt, mid - l + 1, r - mid); if (L <= mid) { update(L, R, C, l, mid, rt << 1); } if (R > mid) { update(L, R, C, mid + 1, r, rt << 1 | 1); } pushUp(rt); } public int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return max[rt]; } int mid = (l + r) >> 1; pushDown(rt, mid - l + 1, r - mid); int left = 0; int right = 0; if (L <= mid) { left = query(L, R, l, mid, rt << 1); } if (R > mid) { right = query(L, R, mid + 1, r, rt << 1 | 1); } return Math.max(left, right); } } public static class Query { public int[] sum1; public int[] sum2; public SegmentTree st; public int m; public Query(int[] arr) { int n = arr.length; m = arr.length + 1; sum1 = new int[m]; sum2 = new int[m]; st = new SegmentTree(m); for (int i = 0; i < n; i++) { sum1[i + 1] = sum1[i] + arr[i]; sum2[i + 1] = sum2[i] + arr[i] * arr[i]; st.update(i + 1, i + 1, arr[i], 1, m, 1); } } public int querySum(int L, int R) { return sum1[R] - sum1[L - 1]; } public int queryAim(int L, int R) { int sumPower2 = querySum(L, R); sumPower2 *= sumPower2; return sum2[R] - sum2[L - 1] + (R - L - 1) * sumPower2; } public int queryMax(int L, int R) { return st.query(L, R, 1, m, 1); } } public static void main(String[] args) { int[] arr = { 1, 1, 2, 3 }; Query q = new Query(arr); System.out.println(q.querySum(1, 3)); System.out.println(q.queryAim(2, 4)); System.out.println(q.queryMax(1, 4)); } }