3165. 不包含相邻元素的子序列的最大和(真心看不懂,先copy)

/**
 * 3165题. 不包含相邻元素的子序列的最大和
 * 给你一个整数数组 nums 和一个二维数组 queries,其中 queries[i] = [posi, xi]。
 * 对于每个查询 i,首先将 nums[posi] 设置为 xi,然后计算查询 i 的答案,该答案为 nums 中 不包含相邻元素 的
 * 子序列
 * 的 最大 和。
 * 返回所有查询的答案之和。
 * 由于最终答案可能非常大,返回其对 109 + 7 取余 的结果。
 * 子序列 是指从另一个数组中删除一些或不删除元素而不改变剩余元素顺序得到的数组。
 * <p>
 * 示例 1:
 * 输入:nums = [3,5,9], queries = [[1,-2],[0,-3]]
 * 输出:21
 * 解释:
 * 执行第 1 个查询后,nums = [3,-2,9],不包含相邻元素的子序列的最大和为 3 + 9 = 12。
 * 执行第 2 个查询后,nums = [-3,-2,9],不包含相邻元素的子序列的最大和为 9 。
 * <p>
 * 示例 2:
 * 输入:nums = [0,-1], queries = [[0,-5]]
 * 输出:0
 * 解释:
 * 执行第 1 个查询后,nums = [-5,-1],不包含相邻元素的子序列的最大和为 0(选择空子序列)。
 * <p>
 * 提示:
 * 1 <= nums.length <= 5 * 104
 * -105 <= nums[i] <= 105
 * 1 <= queries.length <= 5 * 104
 * queries[i] == [posi, xi]
 * 0 <= posi <= nums.length - 1
 * -105 <= xi <= 105
 *
 * @since 2024-10-31
 */
public class LeetCode1031_3165 {
    public static void main(String[] args) {
        // 测试输出
        int[] nums = {3, 5, 9};
        // queries[i] = [posi, xi]。
        int[][] queries = {{1, -2}, {0, -3}};
        System.out.println(maximumSumSubsequence(nums, queries));
    }

    /**
     * 作者:灵茶山艾府
     * 链接:https://leetcode.cn/problems/maximum-sum-of-subsequence-with-non-adjacent-elements/solutions/2790603/fen-zhi-si-xiang-xian-duan-shu-pythonjav-xnhz/
     * 来源:力扣(LeetCode)
     * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     *
     * @param nums
     * @param queries
     * @return
     */
    public static int maximumSumSubsequence(int[] nums, int[][] queries) {
        int n = nums.length;
        // 4 个数分别保存 f00, f01, f10, f11
        long[][] t = new long[2 << (32 - Integer.numberOfLeadingZeros(n))][4];
        build(t, nums, 1, 0, n - 1);

        long ans = 0;
        for (int[] q : queries) {
            update(t, 1, 0, n - 1, q[0], q[1]);
            ans += t[1][3]; // 注意 f11 没有任何限制,也就是整个数组的打家劫舍
        }
        return (int) (ans % 1_000_000_007);
    }

    // 合并左右儿子
    private static void maintain(long[][] t, int o) {
        long[] a = t[o * 2];
        long[] b = t[o * 2 + 1];
        t[o][0] = Math.max(a[0] + b[2], a[1] + b[0]);
        t[o][1] = Math.max(a[0] + b[3], a[1] + b[1]);
        t[o][2] = Math.max(a[2] + b[2], a[3] + b[0]);
        t[o][3] = Math.max(a[2] + b[3], a[3] + b[1]);
    }

    // 用 nums 初始化线段树
    private static void build(long[][] t, int[] nums, int o, int l, int r) {
        if (l == r) {
            t[o][3] = Math.max(nums[l], 0);
            return;
        }
        int m = (l + r) / 2;
        build(t, nums, o * 2, l, m);
        build(t, nums, o * 2 + 1, m + 1, r);
        maintain(t, o);
    }

    // 把 nums[i] 改成 val
    private static void update(long[][] t, int o, int l, int r, int i, int val) {
        if (l == r) {
            t[o][3] = Math.max(val, 0);
            return;
        }
        int m = (l + r) / 2;
        if (i <= m) {
            update(t, o * 2, l, m, i, val);
        } else {
            update(t, o * 2 + 1, m + 1, r, i, val);
        }
        maintain(t, o);
    }

}

posted @   xiaolifc  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示