力扣每日一题3165:不包含相邻元素的子序列的最大和

 题目描述:

3165. 不包含相邻元素的子序列的最大和

给你一个整数数组 nums 和一个二维数组 queries,其中 queries[i] = [posi, xi]

对于每个查询 i,首先将 nums[posi] 设置为 xi,然后计算查询 i 的答案,该答案为 nums 中 不包含相邻元素 的 子序列的 最大 和。

返回所有查询的答案之和。

由于最终答案可能非常大,返回其对( 10^9 + 7 )取余 的结果。

子序列 是指从另一个数组中删除一些或不删除元素而不改变剩余元素顺序得到的数组。

示例 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 。

示例 2:

输入:nums = [0,-1], queries = [[0,-5]]

输出:0

解释:
执行第 1 个查询后,nums = [-5,-1],不包含相邻元素的子序列的最大和为 0(选择空子序列)。

解题思路

        该题核心思想是通过线段树高效地处理区间更新和查询操作,从而在每次更新后快速计算出不包含相邻元素的子序列的最大和。具体步骤如下:

  1. 构建线段树。
  2. 对于每个查询,更新线段树中的相应元素。
  3. 计算更新后的线段树根节点的最大值,并累加到结果中。
  4. 返回最终结果。

代码实

#include <bits/stdc++.h>
using namespace std;
constexpr int MOD = 1e9 + 7;
constexpr long long INF = 1e15;
struct SegmentTree {
    struct Node {
        array<long long, 4> a;
        Node() : a{-INF, -INF, -INF, -INF} {}
        Node operator+(Node& rhs) {
            Node res;
            auto _max = [](auto& x, auto y) {
                x = max(x, y);
            };
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < 4; ++j) {
                    if(a[i] == -INF || rhs.a[j] == -INF) {
                        continue;
                    }
                    int i1 = i / 2, i2 = i % 2;
                    int j1 = j / 2, j2 = j % 2;
                    if (i2 == j1 && i2 == 1) {
                        continue;
                    }
                    int k1 = i1, k2 = j2;
                    _max(res.a[k1 * 2 + k2], a[i] + rhs.a[j]);
                }
            }
            return res;
        }
        long long get() {
            long long res = -INF;
            for (auto x : a) {
                res = max(res, x);
            }
            return res;
        }
    };
    vector<Node> dat;
    SegmentTree(vector<int>& a) {
        int n = a.size();
        int k = 1;
        while (k < n) {
            k *= 2;
        }
        k *= 2;
        dat.resize(k);
        function<void(int, int, int)> init = [&](int p, int l, int r) {
            if (r - l == 1) {
                dat[p].a = {0, -INF, -INF, a[l]};
                return;
            }
            int m = (l + r) / 2;
            int chl = p * 2 + 1, chr = p * 2 + 2;
            init(chl, l, m);
            init(chr, m, r);
            dat[p] = dat[chl] + dat[chr];
        };
        init(0, 0, n);
    }
    void update(int a, int b, int x, int p, int l, int r) {
        if (a <= l && r <= b) {
            dat[p].a = {0, -INF, -INF, x};
            return;
        }
        if (r <= a || b <= l) {
            return;
        }
        int m = (l + r) / 2;
        int chl = p * 2 + 1, chr = p * 2 + 2;
        update(a, b, x, chl, l, m);
        update(a, b, x, chr, m, r);
        dat[p] = dat[chl] + dat[chr];
    }
};

class Solution {
   public:
    int maximumSumSubsequence(vector<int>& nums, vector<vector<int>>& queries) {
        int n = nums.size();
        SegmentTree tr(nums);
        int m = queries.size();
        long long res = 0;
        for (int i = 0; i < m; ++i) {
            int j = queries[i][0], x = queries[i][1];
            tr.update(j, j + 1, x, 0, 0, n);
            res += tr.dat[0].get();
            res %= MOD;
        }
        return (res + MOD) % MOD;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值