【题目链接】
LOJ #6279. 数列分块入门 3
【解析】
考虑到前驱满足区间可加性,于是在每个块内套一个 set,边角的暴力,枚举即可。注意加法标记和边角修改后 set 也要随之修改。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int n, len, a[maxn], b[maxn], t[maxn];
vector<int> v[maxn];
void build()
{
len = sqrt(n);
for(int i = 1; i <= n; i++)
{
b[i] = (i - 1) / len + 1;
v[b[i] ].push_back(a[i]);
}
for(int i = 1; i <= b[n]; i++)
sort(v[i].begin(), v[i].end() );
}
void maintain(int x)
{
int tmp = min(x * len, n);
v[x].clear();
for(int i = (x - 1) * len + 1; i <= tmp; i++)
v[x].push_back(a[i]);
sort(v[x].begin(), v[x].end() );
}
void addb(int l, int r, int c)
{
int tmp = min(b[l] * len, r);
for(int i = l; i <= tmp; i++)
a[i] += c;
maintain(b[l]);
if(b[l] != b[r])
{
for(int i = (b[r] - 1) * len + 1; i <= r; i++)
a[i] += c;
maintain(b[r]);
}
for(int i = b[l] + 1; i < b[r]; i++)
t[i] += c;
}
int query(int l, int r, int c)
{
int tmp = min(b[l] * len, r), ans = -1;
for(int i = l; i <= tmp; i++)
{
if(a[i] + t[b[l] ] >= c)
continue;
ans = max(ans, a[i] + t[b[l] ]);
}
if(b[l] != b[r])
{
for(int i = (b[r] - 1) * len + 1; i <= r; i++)
{
if(a[i] + t[b[r] ] >= c)
continue;
ans = max(ans, a[i] + t[b[r] ]);
}
}
for(int i = b[l] + 1; i < b[r]; i++)
{
int k = lower_bound(v[i].begin(), v[i].end(), c - t[i]) - v[i].begin();
if(k == 0)
continue;
ans = max(ans, v[i][k - 1] + t[i]);
}
return ans;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
scanf("%d" , &a[i]);
build();
for(int i = 1; i <= n; i++)
{
int opt, l, r, c;
scanf("%d%d%d%d", &opt, &l, &r, &c);
switch(opt)
{
case 0:
{
addb(l, r, c);
break;
}
case 1:
{
printf("%d\n", query(l, r, c) );
break;
}
}
}
return 0;
}