求区间内相差最小的两个数的差
分sqrt(n)块,预处理两个数在块内,以及一个数在块内一个数在零散部分的情况,询问时归并排序处理两个数都在零散部分的情况,时间复杂度$O((n+q)\sqrt{n})$。
#include<bits/stdc++.h> const int N=100007,inf=0x7fffffff; char ib[N*30],*ip=ib; int _(){ int x=0; while(*ip<48)++ip; while(*ip>47)x=x*10+*ip++-48; return x; } int abs(int x){return x>0?x:-x;} int min(int a,int b){return a<b?a:b;} void mins(int&a,int b){if(a>b)a=b;} int n,m,B,bid[N],ls[333],rs[333],mb[N],bc=0,f[N][333],ans,bb[333][333],av[N]; struct pos{ int x,y; bool operator<(const pos&w)const{return y<w.y;} }as[N],bs[N]; void block(int l,int r,int c){ std::sort(as+l,as+r+1); ls[c]=l,rs[c]=r; for(int i=l;i<=r;++i)bid[i]=c,av[i]=as[i].y; bb[c][c]=inf; for(int i=l+1;i<=r;++i)mins(bb[c][c],av[i]-av[i-1]); } void get(int l,int r){ int R=rs[bid[l]],xp=0,xs[333]; for(int i=ls[bid[l]];i<=R;++i)if(as[i].x>=l&&as[i].x<=r)xs[xp++]=as[i].y; for(int i=1;i<xp;++i)mins(ans,xs[i]-xs[i-1]); } void get(int l,int pl,int pr,int r){ int L=bid[l],R=bid[r],ys[333],yp=0,yl=0,zs[666],zp=0; for(int i=ls[L];i<=rs[L];++i)if(as[i].x>=l)ys[yp++]=as[i].y; ys[yp]=inf; for(int i=ls[R];i<=rs[R];++i)if(as[i].x<=r){ int y=as[i].y; for(;ys[yl]<y;zs[zp++]=ys[yl++]); zs[zp++]=y; } for(;yl<yp;zs[zp++]=ys[yl++]); for(int i=1;i<zp;++i)mins(ans,zs[i]-zs[i-1]); } int cal(int l,int r){ int zs[666],zp=0; bb[l][r]=min(bb[l+1][r],bb[l][r-1]); int*al=av+ls[l],*ar=av+rs[l]+1; int*bl=av+ls[r],*br=av+rs[r]+1; while(al!=ar&&bl!=br)zs[zp++]=*al<*bl?*al++:*bl++; while(al!=ar)zs[zp++]=*al++; while(bl!=br)zs[zp++]=*bl++; for(int i=1;i<zp;++i)mins(bb[l][r],zs[i]-zs[i-1]); } int main(){ fread(ib,1,sizeof(ib),stdin); n=_(),m=_(); B=sqrt(n); for(int i=1;i<=n;++i){ int y=_(); as[i]=bs[i]=(pos){i,y}; } for(int i=1;i<=n;i+=B)block(i,min(i+B-1,n),++bc); for(int l=bc;l;--l){ for(int r=l+1;r<=bc;++r)cal(l,r); } std::sort(bs+1,bs+n+1); for(int i=1;i<=bc;++i)mb[i]=-inf/2; for(int i=1;i<=n;++i){ int x=bs[i].x,y=bs[i].y; for(int j=1;j<=bc;++j)f[x][j]=y-mb[j]; mb[bid[x]]=y; } for(int i=1;i<=bc;++i)mb[i]=inf; for(int i=n;i;--i){ int x=bs[i].x,y=bs[i].y; for(int j=1;j<=bc;++j)mins(f[x][j],mb[j]-y); for(int j=bid[x]+2;j<=bc;++j)mins(f[x][j],f[x][j-1]); for(int j=bid[x]-2;j>=1;--j)mins(f[x][j],f[x][j+1]); mb[bid[x]]=y; } while(m--){ int l=_(),r=_(); int L=bid[l],R=bid[r];ans=inf; if(L==R)get(l,r); else{ int pl=rs[L],pr=ls[R]; get(l,pl,pr,r); if(R-L>1){ mins(ans,bb[++L][--R]); for(int i=l;i<=pl;++i)mins(ans,f[i][R]); for(int i=pr;i<=r;++i)mins(ans,f[i][L]); } } printf("%d\n",ans); } return 0; }