这是使用hzwer建议的set写的分块代码,set自动排序,支持二分查找,但是常数较大,比我下面写的用vector实现的分块慢了三倍,空间大了10倍。
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
typedef int ll;
const int N = 500007, M = 500007, INF = 0x3f3f3f3f;
ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
//就是要避免重复的权值的,所以用set
int n, m;
int v[N];
int block, bi[N];
int add_tag[N];
set<int>st[N];
void modify(int a, int b, int c)
{
for(int i = a; i <= min(bi[a] * block, b); ++ i){
st[bi[a]].erase(v[i]);
v[i] += c;
st[bi[a]].insert(v[i]);
}
if(bi[a] != bi[b]){
for(int i = (bi[b] - 1) * block + 1; i <= b; ++ i){
st[bi[b]].erase(v[i]);
v[i] += c;
st[bi[b]].insert(v[i]);
}
}
for(int i = bi[a] + 1; i <= bi[b] - 1; ++ i){
add_tag[i] += c;
}
}
int query(int a, int b, int c)
{
int ans = -1;
for(int i = a; i <= min(bi[a] * block, b); ++ i){
int val = v[i] + add_tag[bi[a]];
if(val < c)ans = max(ans, val);
}
if(bi[a] != bi[b]){
for(int i = (bi[b] - 1) * block + 1; i <= b; ++ i){
int val = v[i] + add_tag[bi[b]];
if(val < c)ans = max(ans, val);
}
}
for(int i = bi[a] + 1; i <= bi[b] - 1; ++ i){
int val = c - add_tag[i];
set<int> :: iterator it = st[i].lower_bound(val);
if(it == st[i].begin())continue;
-- it;
ans = max(ans, *it + add_tag[i]);
}
return ans;
}
int main()
{
n = read();
block = sqrt(n);
for(int i = 1; i <= n; ++ i)
v[i] = read();
for(int i = 1; i <= n; ++ i){
bi[i] = (i - 1) / block + 1;
st[bi[i]].insert(v[i]);
}
//cout << "ok" << endl;
for(int i = 1; i <= n; ++i){
int op = read(), a = read(), b = read(), c = read();
if(op == 0){
modify(a, b, c);
}
else if(op == 1){
printf("%d\n", query(a, b, c));
}
}
return 0;
}
vector实现的代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#define x first
#define y second
#define debug(x) cout << x << "ok" << endl
using namespace std;
typedef long long ll;
//typedef __int128 int;oj上可用,编译器上不可用
const int N = 200007, M = 507, INF = 0x3f3f3f3f;
const double eps = 1e-8;
typedef pair<int, int>PII;
int n, m;
int a[N];
int block, cnt;
vector<int>vc[M];
int belong[N];
int add_lz[M];
void pre()//块间无序,块内有序
{
for(int i = 1; i <= cnt; ++ i)
sort(vc[i].begin(), vc[i].end());
}
void update(int block_num)//sqrt(n)
{
vc[block_num].clear();
//上一个块的个数+1到这个块的个数——遍历该块的所有元素
for(int i = (block_num - 1) * block + 1; i <= block_num * block; ++ i)
vc[block_num].push_back(a[i]);
sort(vc[block_num].begin(), vc[block_num].end());
}
void modify(int l, int r, int k)
{
//先处理 l 块
for(int i = l; i <= min(belong[l] * block, r); ++ i){
a[i] += k;
}
update(belong[l]);
if(belong[l] != belong[r]){//不是同一个块,处理 r 块
for(int i = (belong[r] - 1) * block + 1; i <= r; ++ i){
a[i] += k;//先只遍历r所属的块,中间的打标记
}
update(belong[r]);
}
for(int i = belong[l] + 1; i < belong[r]; ++ i){
add_lz[i] += k;
}
}
int query(int l, int r, int maxv)//找小于maxv的最大数(前驱)
{
int ans = -INF;
for(int i = l; i <= min(belong[l] * block, r); ++ i){
if(a[i] + add_lz[belong[i]] < maxv){
ans = max(ans, a[i] + add_lz[belong[i]]);
}
}
if(belong[l] != belong[r]){
for(int i = (belong[r] - 1) * block + 1; i <= r; ++ i){
if(a[i] + add_lz[belong[i]] < maxv){
ans = max(ans, a[i] + add_lz[belong[i]]);
}
}
}
for(int i = belong[l] + 1; i < belong[r]; ++ i){
if(vc[i].at(0) + add_lz[i] >= maxv)//块内最小值+懒惰标记都已经大于maxv那就没有继续的必要
continue;
int k = lower_bound(vc[i].begin(), vc[i].end(), maxv - add_lz[i]) - vc[i].begin();
ans = max(ans, vc[i].at(k - 1) + add_lz[i]);
}
return ans;
}
int main()
{
scanf("%d", &n);
block = sqrt(n);//每个块的个数
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
belong[i] = (i - 1) / block + 1;//从1开始,求当前是第几块
vc[belong[i]].push_back(a[i]);
if(i % block == 1)//注意有头块和尾块,因为n不一定是完全平方数
cnt ++ ;
}
pre();//排序预处理
for(int i = 1; i <= n; ++ i){
int op, l, r, c;
scanf("%d%d%d%d", &op, &l, &r, &c);
if(op == 0){
modify(l, r, c);
}
else {
int res = query(l, r, c);//找前驱
if(res == -INF){
puts("-1");
continue;
}
printf("%d\n", res);
}
}
return 0;
}