分块3
https://loj.ac/problem/6279
1.查找前驱用lower_bound 就可以解决了。
2.放在set集合里做,会更方便
3.其他步骤跟之前的分块一样
直接上代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX=50000+5;
int n,blo;
int a[MAX],bl[MAX],tar[MAX];
set<int> s[505];
ll read()//快读
{
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int l,int r,int c)
{
for(int i=l;i<=min(bl[l]*blo,r);i++)//暴力修改
{
s[bl[l]].erase(a[i]);//先把原有的清楚
a[i]+=c; //暴力加
s[bl[l]].insert(a[i]);//重新插入
}
if(bl[l]!=bl[r])
for(int i=(bl[r]-1)*blo+1;i<=r;i++)
{
s[bl[r]].erase(a[i]);
a[i]+=c;
s[bl[r]].insert(a[i]);
}
for(int i=bl[l]+1;i<=bl[r]-1;i++)//大段打标记
tar[i]+=c;
}
int search(int l,int r,int c)
{
int ans=-1;
for(int i=l;i<=min(bl[l]*blo,r);i++)
{
int v=a[i]+tar[bl[l]];
if(v<c) ans=max(v,ans);
}
if(bl[l]!=bl[r])
for(int i=(bl[r]-1)*blo+1;i<=r;i++)
{
int v=a[i]+tar[bl[r]];
if(v<c) ans=max(v,ans);
}
for(int i=bl[l]+1;i<=bl[r]-1;i++)
{
int x=c-tar[i];
set<int>::iterator it=s[i].lower_bound(x);
if(it==s[i].begin()) continue;//如果在开头,说明没有比他更小的了
--it;//lower_bound是查询大于等于x的第一个数,前一个就是前驱
ans=max(ans,*it+tar[i]);
}
return ans;
}
int main()
{
n=read();
blo=sqrt(n);
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)
{
bl[i]=(i-1)/blo+1;
s[bl[i]].insert(a[i]);
}
for(int i=1;i<=n;i++)
{
int f=read(),l=read(),r=read(),c=read();
if(f==0) add(l,r,c);
if(f==1) cout<<search(l,r,c)<<endl;
}
return 0;
}
求赞ing