适用场景
- 将长区间(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;
}
};