分块入门题-(摘自黄学长的blog)
给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的前驱(比其小的最大元素)。
n<=100000其实是为了区分暴力和一些常数较大的写法。
接着第二题的解法,其实只要把块内查询的二分稍作修改即可。
不过这题其实想表达:可以在块内维护其它结构使其更具有拓展性,比如放一个 set ,这样如果还有插入、删除元素的操作,会更加的方便。
分块的调试检测技巧:
可以生成一些大数据,然后用两份分块大小不同的代码来对拍,还可以根据运行时间尝试调整分块大小,减小常数。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<set> using namespace std; int blo,bl[100005],v[100005],n,lazy[1005]; long long read() { long long x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } set<int> st[1005]; void clear(int x) { st[x].clear(); for(int i=(x-1)*blo+1;i<=min(n,x*blo);i++) st[x].insert(v[i]); //sort(st[x].begin(),st[x].end()); } void change(int l,int r,int val) { for(int i=l;i<=min(bl[l]*blo,r);i++) v[i]+=val; clear(bl[l]); if(bl[l]!=bl[r]) { for(int i=r;i>=(bl[r]-1)*blo+1;i--) v[i]+=val; clear(bl[r]); } for(int i=bl[l]+1;i<=bl[r]-1;i++) lazy[i]+=val; } void query(int l,int r,int x) { int ans=-1; for(int i=l;i<=min(bl[l]*blo,r);i++) if(v[i]+lazy[bl[l]]<x) ans=max(ans,v[i]+lazy[bl[l]]); if(bl[l]!=bl[r]) { for(int i=r;i>=(bl[r]-1)*blo+1;i--) if(v[i]+lazy[bl[r]]<x) ans-max(ans,v[i])+lazy[bl[r]]; } for(int i=bl[l]+1;i<=bl[r]-1;i++) { int c=x-lazy[i]; set<int>::iterator it1=st[i].lower_bound(c); if(st[i].begin()==it1) continue; it1--; ans=max(ans,*it1+lazy[i]); } if(ans==-1) printf("impossible\n");else printf("%d\n",ans); } int main() { n=read(); blo=sqrt(n); for(int i=1;i<=n;i++) v[i]=read(),bl[i]=(i-1)/blo+1,st[bl[i]].insert(v[i]); //for(int i=1;i<=bl[n];i++) //sort(st[i].begin(),st[i].end()); char char_[10]; for(int i=1;i<=n;i++) { scanf("%s",&char_); if(char_[0]==‘c‘) { int l,r,val; scanf("%d %d %d",&l,&r,&val); change(l,r,val); }else{ int l,r,x; scanf("%d %d %d",&l,&r,&x); query(l,r,x); } } return 0; }
时间: 2024-11-10 14:49:42