题目链接:https://loj.ac/problem/6279
题目描述
给出一个长为 nn 的数列,以及 nn 个操作,操作涉及区间加法,询问区间内小于某个值 xx 的前驱(比其小的最大元素)。
输入格式
第一行输入一个数字 nn。
第二行输入 nn 个数字,第 ii 个数字为 a_iai,以空格隔开。
接下来输入 nn 行询问,每行输入四个数字 \mathrm{opt}opt、ll、rr、cc,以空格隔开。
若 \mathrm{opt} = 0opt=0,表示将位于 [l, r][l,r] 的之间的数字都加 cc。
若 \mathrm{opt} = 1opt=1,表示询问 [l, r][l,r] 中 cc 的前驱的值(不存在则输出 -1−1)。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4
样例输出
3
-1
思路:第三题和第二题思路是样的,因为是要找c的前驱,暴力找左右不完整块的比c小最大值,再二分找完整块比c小最大值,取其中最大即可。
ac代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int s[maxn],flag[maxn],pos[maxn],ans,tag,n,m;
vector<int>v[1010];
void reset(int x)//用于对不完整块排序
{
v[pos[x]].clear();
for(int i=(pos[x]-1)*m+1;i<=min(pos[x]*m,n);i++)
v[pos[x]].push_back(s[i]);
sort(v[pos[x]].begin(),v[pos[x]].end());
}
void update(int l,int r,int c)//更新值,第一个操作
{
for(int i=l;i<=min(pos[l]*m,r);i++)//暴力加
s[i]+=c;
reset(l);
if(pos[l]!=pos[r])
{
for(int i=(pos[r]-1)*m+1;i<=r;i++)//暴力加
s[i]+=c;
reset(r);
}
for(int i=pos[l]+1;i<=pos[r]-1;i++)//b数组储存完整块的加值
flag[i]+=c;
}
void query(int l,int r,int x)
{
tag=0;//标记是否找到比c小的值
ans=-inf;
for(int i=l;i<=min(pos[l]*m,r);i++)//暴力找左边不完整块
{
if(s[i]+flag[pos[l]]<x)
{
ans=max(s[i]+flag[pos[l]],ans);
tag=1;
}
}
if(pos[l]!=pos[r])//暴力找右边不完整块
{
for(int i=(pos[r]-1)*m+1;i<=r;i++)
{
if(s[i]+flag[pos[r]]<x)
{
ans=max(ans,s[i]+flag[pos[r]]);
tag=1;
}
}
}
for(int i=pos[l]+1;i<=pos[r]-1;i++)//整块用二分查找
{
int c=x-flag[i];
int k=lower_bound(v[i].begin(),v[i].end(),c)-v[i].begin();
if(k!=0&&v[i][k-1]+flag[i]<x)//不要忘了加回整块该加的值
{
tag=1;
ans=max(ans,v[i][k-1]+flag[i]);
}
}
if(tag)
printf("%d\n",ans);
else
printf("-1\n");
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&s[i]);
m=sqrt(n);//块的大小
for(int i=1;i<=n;i++)
pos[i]=(i-1)/m+1,v[pos[i]].push_back(s[i]);//每个数块的序号并储存在vector
for(int i=1;i<=pos[n];i++)
sort(v[i].begin(),v[i].end());//整块排序
int opt,l,r,c;
for(int i=0;i<n;i++)
{
scanf("%d%d%d%d",&opt,&l,&r,&c);
if(opt==0)
update(l,r,c);
else
query(l,r,c);
}
return 0;
}