diff --git a/src/main/java/g3101_3200/s3165_maximum_sum_of_subsequence_with_non_adjacent_elements/Solution.java b/src/main/java/g3101_3200/s3165_maximum_sum_of_subsequence_with_non_adjacent_elements/Solution.java index 8de741c4b..495edb1ac 100644 --- a/src/main/java/g3101_3200/s3165_maximum_sum_of_subsequence_with_non_adjacent_elements/Solution.java +++ b/src/main/java/g3101_3200/s3165_maximum_sum_of_subsequence_with_non_adjacent_elements/Solution.java @@ -1,125 +1,77 @@ package g3101_3200.s3165_maximum_sum_of_subsequence_with_non_adjacent_elements; // #Hard #Array #Dynamic_Programming #Divide_and_Conquer #Segment_Tree -// #2024_06_02_Time_1927_ms_(87.75%)_Space_82.1_MB_(5.31%) - -import java.util.stream.Stream; +// #2024_11_09_Time_64_ms_(100.00%)_Space_64.1_MB_(97.01%) public class Solution { + private static final int YY = 0; + private static final int YN = 1; + private static final int NY = 2; + private static final int NN = 3; private static final int MOD = 1_000_000_007; public int maximumSumSubsequence(int[] nums, int[][] queries) { - int ans = 0; - SegTree segTree = new SegTree(nums); - for (int[] q : queries) { - int idx = q[0]; - int val = q[1]; - segTree.update(idx, val); - ans = (ans + segTree.getMax()) % MOD; + long[][] tree = build(nums); + long result = 0; + for (int i = 0; i < queries.length; ++i) { + result += set(tree, queries[i][0], queries[i][1]); + result %= MOD; } - return ans; + return (int) result; } - static class SegTree { - private static class Record { - int takeFirstTakeLast; - int takeFirstSkipLast; - int skipFirstSkipLast; - int skipFirstTakeLast; - - public Integer getMax() { - return Stream.of( - this.takeFirstSkipLast, - this.takeFirstTakeLast, - this.skipFirstSkipLast, - this.skipFirstTakeLast) - .max(Integer::compare) - .orElse(null); - } - - public Integer skipLast() { - return Stream.of(this.takeFirstSkipLast, this.skipFirstSkipLast) - .max(Integer::compare) - .orElse(null); - } - - public Integer takeLast() { - return Stream.of(this.skipFirstTakeLast, this.takeFirstTakeLast) - .max(Integer::compare) - .orElse(null); - } + private static long[][] build(int[] nums) { + final int len = nums.length; + int size = 1; + while (size < len) { + size <<= 1; } - - private final Record[] seg; - private final int[] nums; - - public SegTree(int[] nums) { - this.nums = nums; - seg = new Record[4 * nums.length]; - for (int i = 0; i < 4 * nums.length; ++i) { - seg[i] = new Record(); - } - build(0, nums.length - 1, 0); + long[][] tree = new long[size * 2][4]; + for (int i = 0; i < len; ++i) { + tree[size + i][YY] = nums[i]; } - - private void build(int i, int j, int k) { - if (i == j) { - seg[k].takeFirstTakeLast = nums[i]; - return; - } - int mid = (i + j) >> 1; - build(i, mid, 2 * k + 1); - build(mid + 1, j, 2 * k + 2); - merge(k); - } - - // merge [2*k+1, 2*k+2] into k - private void merge(int k) { - seg[k].takeFirstSkipLast = + for (int i = size - 1; i > 0; --i) { + tree[i][YY] = Math.max( - seg[2 * k + 1].takeFirstSkipLast + seg[2 * k + 2].skipLast(), - seg[2 * k + 1].takeFirstTakeLast + seg[2 * k + 2].skipFirstSkipLast); - - seg[k].takeFirstTakeLast = + tree[2 * i][YY] + tree[2 * i + 1][NY], + tree[2 * i][YN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); + tree[i][YN] = Math.max( - seg[2 * k + 1].takeFirstSkipLast + seg[2 * k + 2].takeLast(), - seg[2 * k + 1].takeFirstTakeLast + seg[2 * k + 2].skipFirstTakeLast); - - seg[k].skipFirstTakeLast = + tree[2 * i][YY] + tree[2 * i + 1][NN], + tree[2 * i][YN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); + tree[i][NY] = Math.max( - seg[2 * k + 1].skipFirstSkipLast + seg[2 * k + 2].takeLast(), - seg[2 * k + 1].skipFirstTakeLast + seg[2 * k + 2].skipFirstTakeLast); - - seg[k].skipFirstSkipLast = + tree[2 * i][NY] + tree[2 * i + 1][NY], + tree[2 * i][NN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); + tree[i][NN] = Math.max( - seg[2 * k + 1].skipFirstSkipLast + seg[2 * k + 2].skipLast(), - seg[2 * k + 1].skipFirstTakeLast + seg[2 * k + 2].skipFirstSkipLast); - } - - // child -> parent - public void update(int idx, int val) { - int i = 0; - int j = nums.length - 1; - int k = 0; - update(idx, val, k, i, j); - } - - private void update(int idx, int val, int k, int i, int j) { - if (i == j) { - seg[k].takeFirstTakeLast = val; - return; - } - int mid = (i + j) >> 1; - if (idx <= mid) { - update(idx, val, 2 * k + 1, i, mid); - } else { - update(idx, val, 2 * k + 2, mid + 1, j); - } - merge(k); + tree[2 * i][NY] + tree[2 * i + 1][NN], + tree[2 * i][NN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); } + return tree; + } - public int getMax() { - return seg[0].getMax(); + private static long set(long[][] tree, int idx, int val) { + int size = tree.length / 2; + tree[size + idx][YY] = val; + for (int i = (size + idx) / 2; i > 0; i /= 2) { + tree[i][YY] = + Math.max( + tree[2 * i][YY] + tree[2 * i + 1][NY], + tree[2 * i][YN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); + tree[i][YN] = + Math.max( + tree[2 * i][YY] + tree[2 * i + 1][NN], + tree[2 * i][YN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); + tree[i][NY] = + Math.max( + tree[2 * i][NY] + tree[2 * i + 1][NY], + tree[2 * i][NN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); + tree[i][NN] = + Math.max( + tree[2 * i][NY] + tree[2 * i + 1][NN], + tree[2 * i][NN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); } + return Math.max(tree[1][YY], Math.max(tree[1][YN], Math.max(tree[1][NY], tree[1][NN]))); } }