给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,询问区间内小于某个值 xx 的前驱(比其小的最大元素)。
Input
第一行输入一个数字 n,1≤n≤100000n,1≤n≤100000。
第二行输入 nn 个非负整数,第 ii个数字为 ai(0≤ai≤109)ai(0≤ai≤109)以空格隔开。
接下来输入nn 行询问,每行输入四个数字 opt、l、r、c(c>0)opt、l、r、c(c>0),以空格隔开。
若 oopt=0opt=0,表示将位于[l,r][l,r]的之间的数字都加 cc。
若 opt=1opt=1,表示询问[l,r][l,r]中 cc 的前驱的值(不存在则输出 −1−1)。
Output
对于每次询问,输出一行一个数字表示答案。
保证所有数据在int范围内
Sample Input
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
Sample Output
3
-1
Hint
SOLUTION:
最初一看到这个题的这种格式就准备用树状数组来做的,可是做到询问前驱的时候就发现做不好了,然后就瞄了一下了学长的题解,才发现要用分块做,分块呢我只知道它的模板,~~~(我真的好菜哎^^),然后我就套模板一写,可提交就T了,中间又错了好多次,最后又看了看学长的代码,学长是用的vector来存每一块的数,左右两端残块暴力处理,中间的整块(如果有的话)一块块的处理,这时更新的时候就没有对原数组直接+val,而是维护一个lazy数组,表示每一块要加的数是多少,比较的时候用val-lazy[i]与原数组比较,如果有比它小的最大的数则存在前缀,且为找到的原数组的那个数+lazy[i],否则就没有。。。。。。。最后明白这才叫分块嘛,中间一块一块的处理,像我最初中间还是一个一个点处理,那分块意义何在。。。。。。。
CODE:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=100001;
int belong[maxn],l[maxn],r[maxn],b[maxn];
int lazy[maxn];
int block,num;
int n;
vector<int>s[1010];
void build()
{
block=(int)sqrt(n);
num=n/block;
if(n%block) num++;
for(int i=1;i<=num;i++)
l[i]=(i-1)*block+1,r[i]=i*block;
r[num]=n;//
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
belong[i]=(i-1)/block+1;
s[belong[i]].push_back(b[i]);
}
for(int i=1;i<=belong[n];i++) sort(s[i].begin(),s[i].end());
}
void update(int ll,int rr,int val)
{
int first=belong[ll];
int last=belong[rr];
for(int i=ll;i<=min(belong[ll]*block,rr);i++)
b[i]+=val;
s[belong[ll]].clear();
for(int i=(belong[ll]-1)*block+1;i<=min(belong[ll]*block,n);i++)
s[belong[ll]].push_back(b[i]);
sort(s[belong[ll]].begin(),s[belong[ll]].end());//左边残块
if(belong[ll]==belong[rr]) return;//如果只有一个残块修改完毕
for(int i=(belong[rr]-1)*block;i<=rr;i++)
b[i]+=val;
s[belong[rr]].clear();
for(int i=(belong[rr]-1)*block+1;i<=min(belong[rr]*block,n);i++)
s[belong[rr]].push_back(b[i]);
sort(s[belong[rr]].begin(),s[belong[rr]].end());//右边残块
for(int i=first+1;i<=last-1;i++)
lazy[i]+=val;//中间的整块用lazy维护而不对原数组直接+
}
int query(int ll,int rr,int val)
{
int first=belong[ll];
int last=belong[rr];
int _max=-1;
for(int i=ll;i<=min(r[belong[ll]],rr);i++)
if(b[i]+lazy[belong[i]]<val)
_max=max(_max,b[i]+lazy[belong[i]]);
if(first!=last)
{
for(int i=l[belong[rr]];i<=rr;i++)
if(b[i]+lazy[belong[i]]<val)
_max=max(b[i]+lazy[belong[i]],_max);
}
for(int i=first+1;i<=last-1;i++)
{
auto it=lower_bound(s[i].begin(),s[i].end(),val-lazy[i]);
if(it==s[i].begin()) continue;
--it;
_max=max(_max,*it+lazy[i]);
}
return _max;
}
int main()
{
//ios::sync_with_stdio(0),cin.tie(0);
while(~scanf("%d",&n)){
build();
int m=n;
int op,x,y,k;
while(m--)
{
scanf("%d%d%d%d",&op,&x,&y,&k);
if(op==0)
{
update(x,y,k);
}
else if(op==1)
{
printf("%d
",query(x,y,k));
}
}
}
return 0;
}