分块优化思想

适用场景

  1. 将长区间(n)的顺序枚举查询优化至 n \sqrt{n} n 个块的顺序枚举,这样单次查询枚举的数量会直接从O(n)降低至O( n \sqrt{n} n )。
    实现手段:
    (1)预处理所有分块,并处理出每个分块内元素跳跃至下一个分块的指针。
    题目链接:
    分块优化大法
    这道题目还可以用倍增来做,速度更快
    (2)预处理所有分块,并构造如何汇总分块得到总区间答案的方法。
    当每个查询单点更新时,花费O( n \sqrt{n} n )时间可以更新子块的答案,最后再花费O( n \sqrt{n} n )时间汇总所有分块计算出总答案
    注意事项:这种解法容易卡常数,注意优化
    题目链接
class Solution {
    const int mo = 1e9+7;
    typedef long long ll;
    int func(vector<int>&nums,int a,int b){
        if(a > b)   return 0;
        int len = b-a+1;
        if(len == 1){
            return nums[a] > 0 ? nums[a] : 0; 
        }
        vector<int>dp(2,0);
        dp[1] = nums[a];
        for(int i = a+1;i<=b;i++){
            int pre_0 = dp[0],pre_1 = dp[1];
            dp[0] = max(pre_0,pre_1);
            dp[1] = pre_0+nums[i];
        }
        return max(dp[0],dp[1]);
    }
    ll generate_res(vector<vector<int>>&sub,int k){
        ll a = sub[0][1];
        ll b = sub[0][3];
        for(int i = 1;i<=k;i++){
            ll a1 = a,b1 = b;
            a = max(a1+sub[i][1],b1+sub[i][2]);
            b = max(a1+sub[i][3],b1+sub[i][0]);
        }
        return b;
    }
    
public:
    int maximumSumSubsequence(vector<int>& nums, vector<vector<int>>& queries) {
        int n = nums.size();
        int m = sqrt(n);
        
        vector<int>idx(n,0);
        for(int i = 0;i<n;i++){
            idx[i] = i/m;
        }
        int k = (n-1)/m;
        vector<int>v(4,0);
        vector<vector<int>>sub(k+1,v);
        for(int i = 0;i<=k;i++){
            int st = i*m,end = min((i+1)*m-1,n-1);
            sub[i][0] = func(nums,st+1,end);
            sub[i][1] = func(nums,st,end-1);
            sub[i][2] = func(nums,st+1,end-1);
            sub[i][3] = func(nums,st,end);
        }
        ll ret = 0;
        for(auto q : queries){
            int pos = q[0],x = q[1];
            nums[pos] = x;
            int i = pos/m;
            int st = i*m,end = min((i+1)*m-1,n-1);
            sub[i][0] = func(nums,st+1,end);
            sub[i][1] = func(nums,st,end-1);
            sub[i][2] = func(nums,st+1,end-1);
            sub[i][3] = func(nums,st,end);
            ret = (ret+generate_res(sub,k))%mo;
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值