思路:分块。分成sqrt(n)个块,将每个块里的数存入vector中,排序。更新时,对于残缺的块,暴力更新即可,完整的块可以加懒惰标记;查询时类似,对于残缺的块暴力查找,完整的块利用二分。(代码有点丑。。)
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
typedef long long ll;
ll a[MAX],lazy[500];
int b[MAX],siz,cnt,n;
vector<ll>block[500];
void rebuild(int th)
{
block[th].clear();
for(int i=(th-1)*siz+1;i<=th*siz&&i<=n;i++)block[th].push_back(a[i]);
sort(block[th].begin(),block[th].end());
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
siz=sqrt(n);
cnt=n/siz;
if(n%siz)cnt++;
for(int i=1;i<=n;i++)
{
b[i]=(i-1)/siz+1;
block[b[i]].push_back(a[i]);
}
for(int i=1;i<=cnt;i++)sort(block[i].begin(),block[i].end());
for(int i=1;i<=n;i++)
{
int op,x,y,z;
scanf("%d%d%d%d",&op,&x,&y,&z);
if(op==0)
{
for(int j=x;j<=b[x]*siz&&j<=y;j++)a[j]+=z;
rebuild(b[x]);
for(int j=b[x]+1;j*siz<=n&&j*siz<=y;j++)lazy[j]+=z;
if(b[x]!=b[y]&&y%siz)
{
for(int j=(b[y]-1)*siz+1;j<=y;j++)a[j]+=z;
rebuild(b[y]);
}
}
else
{
ll ans=-1;
for(int j=x;j<=b[x]*siz&&j<=y;j++)
{
if(a[j]+lazy[b[x]]<z)ans=max(ans,a[j]+lazy[b[x]]);
}
for(int j=b[x]+1;j*siz<=y;j++)
{
int index=lower_bound(block[j].begin(),block[j].end(),z-lazy[j])-block[j].begin();
if(index>0)ans=max(ans,block[j][index-1]+lazy[j]);
}
if(b[x]!=b[y]&&y%siz)
{
for(int j=(b[y]-1)*siz+1;j<=y;j++)
{
if(a[j]+lazy[b[y]]<z)ans=max(ans,a[j]+lazy[b[y]]);
}
}
printf("%lld\n",ans);
}
}
return 0;
}