题目链接
题意
给出一个长为 n n n的数列,以及 n n n个操作,操作涉及区间加法,询问区间内小于某个值 x x x的前驱(比其小的最大元素)。
思路
分块区间修改板题。
分块的时候,就对每一个块进行排序,查找时,边块角块依旧暴力,整块使用
l
o
w
e
r
_
b
o
u
n
d
lower\_bound
lower_bound和
u
p
p
e
r
_
b
o
u
n
d
upper\_bound
upper_bound 二分查找。
注意,边块角块修改后所在块要重新排序。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,block,cnt;
int a[100010],addv[400],belong[100010];
vector<int> vc[400];
void Sort() {
for(int i=1; i<=cnt; i++) {
sort(vc[i].begin(),vc[i].end());
}
}
void update(int blockn) {
vc[blockn].clear();
for(int i=(blockn-1)*block+1; i<=blockn*block; i++) {
vc[blockn].push_back(a[i]);
}
sort(vc[blockn].begin(),vc[blockn].end());
}
void modify(int l,int r,int add) {
for(int i=l; i<=min(belong[l]*block,r); i++) {
a[i]+=add;
}
update(belong[l]);
if(belong[l]!=belong[r]) {
for(int i=(belong[r]-1)*block+1; i<=r; i++) {
a[i]+=add;
}
update(belong[r]);
}
for(int i=belong[l]+1; i<belong[r]; i++) {
addv[i]+=add;
}
}
int query(int l,int r,int maxn) {
int ans=-inf;
for(int i=l; i<=min(belong[l]*block,r); i++) {
if(a[i]+addv[belong[i]]<maxn) {
ans=max(ans,a[i]+addv[belong[i]]);
}
}
if(belong[l]!=belong[r]) {
for(int i=(belong[r]-1)*block+1; i<=r; i++) {
if(a[i]+addv[belong[i]]<maxn) {
ans=max(ans,a[i]+addv[belong[i]]);
}
}
}
for(int i=belong[l]+1; i<belong[r]; i++) {
if(vc[i].at(0)+addv[i]>=maxn) {
continue;
}
int k=lower_bound(vc[i].begin(),vc[i].end(),maxn-addv[i])-vc[i].begin();
ans=max(ans,vc[i].at(k-1)+addv[i]);
}
return ans;
}
int main() {
int n;
scanf("%d",&n);
block=sqrt(n);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
belong[i]=(i-1)/block+1;
vc[belong[i]].push_back(a[i]);
if(i%block==1) {
cnt++;
}
}
Sort();
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 k=query(l,r,c);
if(k==-inf) {
printf("-1\n");
continue;
}
printf("%d\n",k);
}
}
return 0;
}