|  | 
| 1 | 1 | package g3101_3200.s3165_maximum_sum_of_subsequence_with_non_adjacent_elements; | 
| 2 | 2 | 
 | 
| 3 | 3 | // #Hard #Array #Dynamic_Programming #Divide_and_Conquer #Segment_Tree | 
| 4 |  | -// #2024_06_02_Time_1927_ms_(87.75%)_Space_82.1_MB_(5.31%) | 
| 5 |  | - | 
| 6 |  | -import java.util.stream.Stream; | 
|  | 4 | +// #2024_11_09_Time_64_ms_(100.00%)_Space_64.1_MB_(97.01%) | 
| 7 | 5 | 
 | 
| 8 | 6 | public class Solution { | 
|  | 7 | +    private static final int YY = 0; | 
|  | 8 | +    private static final int YN = 1; | 
|  | 9 | +    private static final int NY = 2; | 
|  | 10 | +    private static final int NN = 3; | 
| 9 | 11 |     private static final int MOD = 1_000_000_007; | 
| 10 | 12 | 
 | 
| 11 | 13 |     public int maximumSumSubsequence(int[] nums, int[][] queries) { | 
| 12 |  | -        int ans = 0; | 
| 13 |  | -        SegTree segTree = new SegTree(nums); | 
| 14 |  | -        for (int[] q : queries) { | 
| 15 |  | -            int idx = q[0]; | 
| 16 |  | -            int val = q[1]; | 
| 17 |  | -            segTree.update(idx, val); | 
| 18 |  | -            ans = (ans + segTree.getMax()) % MOD; | 
|  | 14 | +        long[][] tree = build(nums); | 
|  | 15 | +        long result = 0; | 
|  | 16 | +        for (int i = 0; i < queries.length; ++i) { | 
|  | 17 | +            result += set(tree, queries[i][0], queries[i][1]); | 
|  | 18 | +            result %= MOD; | 
| 19 | 19 |         } | 
| 20 |  | -        return ans; | 
|  | 20 | +        return (int) result; | 
| 21 | 21 |     } | 
| 22 | 22 | 
 | 
| 23 |  | -    static class SegTree { | 
| 24 |  | -        private static class Record { | 
| 25 |  | -            int takeFirstTakeLast; | 
| 26 |  | -            int takeFirstSkipLast; | 
| 27 |  | -            int skipFirstSkipLast; | 
| 28 |  | -            int skipFirstTakeLast; | 
| 29 |  | - | 
| 30 |  | -            public Integer getMax() { | 
| 31 |  | -                return Stream.of( | 
| 32 |  | -                                this.takeFirstSkipLast, | 
| 33 |  | -                                this.takeFirstTakeLast, | 
| 34 |  | -                                this.skipFirstSkipLast, | 
| 35 |  | -                                this.skipFirstTakeLast) | 
| 36 |  | -                        .max(Integer::compare) | 
| 37 |  | -                        .orElse(null); | 
| 38 |  | -            } | 
| 39 |  | - | 
| 40 |  | -            public Integer skipLast() { | 
| 41 |  | -                return Stream.of(this.takeFirstSkipLast, this.skipFirstSkipLast) | 
| 42 |  | -                        .max(Integer::compare) | 
| 43 |  | -                        .orElse(null); | 
| 44 |  | -            } | 
| 45 |  | - | 
| 46 |  | -            public Integer takeLast() { | 
| 47 |  | -                return Stream.of(this.skipFirstTakeLast, this.takeFirstTakeLast) | 
| 48 |  | -                        .max(Integer::compare) | 
| 49 |  | -                        .orElse(null); | 
| 50 |  | -            } | 
|  | 23 | +    private static long[][] build(int[] nums) { | 
|  | 24 | +        final int len = nums.length; | 
|  | 25 | +        int size = 1; | 
|  | 26 | +        while (size < len) { | 
|  | 27 | +            size <<= 1; | 
| 51 | 28 |         } | 
| 52 |  | - | 
| 53 |  | -        private final Record[] seg; | 
| 54 |  | -        private final int[] nums; | 
| 55 |  | - | 
| 56 |  | -        public SegTree(int[] nums) { | 
| 57 |  | -            this.nums = nums; | 
| 58 |  | -            seg = new Record[4 * nums.length]; | 
| 59 |  | -            for (int i = 0; i < 4 * nums.length; ++i) { | 
| 60 |  | -                seg[i] = new Record(); | 
| 61 |  | -            } | 
| 62 |  | -            build(0, nums.length - 1, 0); | 
|  | 29 | +        long[][] tree = new long[size * 2][4]; | 
|  | 30 | +        for (int i = 0; i < len; ++i) { | 
|  | 31 | +            tree[size + i][YY] = nums[i]; | 
| 63 | 32 |         } | 
| 64 |  | - | 
| 65 |  | -        private void build(int i, int j, int k) { | 
| 66 |  | -            if (i == j) { | 
| 67 |  | -                seg[k].takeFirstTakeLast = nums[i]; | 
| 68 |  | -                return; | 
| 69 |  | -            } | 
| 70 |  | -            int mid = (i + j) >> 1; | 
| 71 |  | -            build(i, mid, 2 * k + 1); | 
| 72 |  | -            build(mid + 1, j, 2 * k + 2); | 
| 73 |  | -            merge(k); | 
| 74 |  | -        } | 
| 75 |  | - | 
| 76 |  | -        // merge [2*k+1, 2*k+2] into k | 
| 77 |  | -        private void merge(int k) { | 
| 78 |  | -            seg[k].takeFirstSkipLast = | 
|  | 33 | +        for (int i = size - 1; i > 0; --i) { | 
|  | 34 | +            tree[i][YY] = | 
| 79 | 35 |                     Math.max( | 
| 80 |  | -                            seg[2 * k + 1].takeFirstSkipLast + seg[2 * k + 2].skipLast(), | 
| 81 |  | -                            seg[2 * k + 1].takeFirstTakeLast + seg[2 * k + 2].skipFirstSkipLast); | 
| 82 |  | - | 
| 83 |  | -            seg[k].takeFirstTakeLast = | 
|  | 36 | +                            tree[2 * i][YY] + tree[2 * i + 1][NY], | 
|  | 37 | +                            tree[2 * i][YN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); | 
|  | 38 | +            tree[i][YN] = | 
| 84 | 39 |                     Math.max( | 
| 85 |  | -                            seg[2 * k + 1].takeFirstSkipLast + seg[2 * k + 2].takeLast(), | 
| 86 |  | -                            seg[2 * k + 1].takeFirstTakeLast + seg[2 * k + 2].skipFirstTakeLast); | 
| 87 |  | - | 
| 88 |  | -            seg[k].skipFirstTakeLast = | 
|  | 40 | +                            tree[2 * i][YY] + tree[2 * i + 1][NN], | 
|  | 41 | +                            tree[2 * i][YN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); | 
|  | 42 | +            tree[i][NY] = | 
| 89 | 43 |                     Math.max( | 
| 90 |  | -                            seg[2 * k + 1].skipFirstSkipLast + seg[2 * k + 2].takeLast(), | 
| 91 |  | -                            seg[2 * k + 1].skipFirstTakeLast + seg[2 * k + 2].skipFirstTakeLast); | 
| 92 |  | - | 
| 93 |  | -            seg[k].skipFirstSkipLast = | 
|  | 44 | +                            tree[2 * i][NY] + tree[2 * i + 1][NY], | 
|  | 45 | +                            tree[2 * i][NN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); | 
|  | 46 | +            tree[i][NN] = | 
| 94 | 47 |                     Math.max( | 
| 95 |  | -                            seg[2 * k + 1].skipFirstSkipLast + seg[2 * k + 2].skipLast(), | 
| 96 |  | -                            seg[2 * k + 1].skipFirstTakeLast + seg[2 * k + 2].skipFirstSkipLast); | 
| 97 |  | -        } | 
| 98 |  | - | 
| 99 |  | -        // child -> parent | 
| 100 |  | -        public void update(int idx, int val) { | 
| 101 |  | -            int i = 0; | 
| 102 |  | -            int j = nums.length - 1; | 
| 103 |  | -            int k = 0; | 
| 104 |  | -            update(idx, val, k, i, j); | 
| 105 |  | -        } | 
| 106 |  | - | 
| 107 |  | -        private void update(int idx, int val, int k, int i, int j) { | 
| 108 |  | -            if (i == j) { | 
| 109 |  | -                seg[k].takeFirstTakeLast = val; | 
| 110 |  | -                return; | 
| 111 |  | -            } | 
| 112 |  | -            int mid = (i + j) >> 1; | 
| 113 |  | -            if (idx <= mid) { | 
| 114 |  | -                update(idx, val, 2 * k + 1, i, mid); | 
| 115 |  | -            } else { | 
| 116 |  | -                update(idx, val, 2 * k + 2, mid + 1, j); | 
| 117 |  | -            } | 
| 118 |  | -            merge(k); | 
|  | 48 | +                            tree[2 * i][NY] + tree[2 * i + 1][NN], | 
|  | 49 | +                            tree[2 * i][NN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); | 
| 119 | 50 |         } | 
|  | 51 | +        return tree; | 
|  | 52 | +    } | 
| 120 | 53 | 
 | 
| 121 |  | -        public int getMax() { | 
| 122 |  | -            return seg[0].getMax(); | 
|  | 54 | +    private static long set(long[][] tree, int idx, int val) { | 
|  | 55 | +        int size = tree.length / 2; | 
|  | 56 | +        tree[size + idx][YY] = val; | 
|  | 57 | +        for (int i = (size + idx) / 2; i > 0; i /= 2) { | 
|  | 58 | +            tree[i][YY] = | 
|  | 59 | +                    Math.max( | 
|  | 60 | +                            tree[2 * i][YY] + tree[2 * i + 1][NY], | 
|  | 61 | +                            tree[2 * i][YN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); | 
|  | 62 | +            tree[i][YN] = | 
|  | 63 | +                    Math.max( | 
|  | 64 | +                            tree[2 * i][YY] + tree[2 * i + 1][NN], | 
|  | 65 | +                            tree[2 * i][YN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); | 
|  | 66 | +            tree[i][NY] = | 
|  | 67 | +                    Math.max( | 
|  | 68 | +                            tree[2 * i][NY] + tree[2 * i + 1][NY], | 
|  | 69 | +                            tree[2 * i][NN] + Math.max(tree[2 * i + 1][YY], tree[2 * i + 1][NY])); | 
|  | 70 | +            tree[i][NN] = | 
|  | 71 | +                    Math.max( | 
|  | 72 | +                            tree[2 * i][NY] + tree[2 * i + 1][NN], | 
|  | 73 | +                            tree[2 * i][NN] + Math.max(tree[2 * i + 1][YN], tree[2 * i + 1][NN])); | 
| 123 | 74 |         } | 
|  | 75 | +        return Math.max(tree[1][YY], Math.max(tree[1][YN], Math.max(tree[1][NY], tree[1][NN]))); | 
| 124 | 76 |     } | 
| 125 | 77 | } | 
0 commit comments