离线,从小到大枚举右端点,维护左端点的答案,那么当右端点从$r-1$变为$r$时,即在原来的基础上考虑其中一个数为$a_{r}$的答案,并对原来的答案取$min$
考虑另一个数为$a_{i}$,这里仅考虑$a_{r}le a_{i}$的情况($a_{r}ge a_{i}$类似):
此时,先找到最大的$1le i_{1}<r$使得$a_{r}le a_{i_{1}}$,不妨先对$[1,i_{1}]$的答案都用$a_{i_{1}}-a_{r}$去更新
接下来,注意到如果$a_{i_{2}}ge lceilfrac{a_{r}+a_{i_{1}}}{2} ceil$则有$|a_{i_{1}}-a_{i_{2}}|le a_{i_{2}}-a_{r}$,即其一定没有意义,那么只需要找到最大的$1le i_{2}<i_{1}$使得$a_{r}le a_{i_{2}}<lceilfrac{a_{r}+a_{i_{1}}}{2} ceil$即可
重复此过程,即不断找到最大的$1le i_{t}<i_{t-1}$使得$a_{r}le a_{i_{t}}<lceilfrac{a_{r}+a_{i_{t-1}}}{2} ceil$,由于$0le a_{i_{t}}-a_{r}<lceilfrac{a_{t-1}-a_{r}}{2} ceil$,因此最多找$o(log V)$次,每一次用线段树维护可以做到$o(log V)$(其中$V$为值域)
(注意查找有上下限,不能直接在线段树上二分,需要建立可持久化权值线段树来查询)
总复杂度即$o(nlog^{2}V+mlog n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 vector<pair<int,int> >v[N]; 8 int V,n,m,x,y,a[N],rt[N],mx[N*40],ls[N*40],rs[N*40],f[N<<2],ans[N<<2]; 9 void update(int k,int l,int r,int x,int y,int z){ 10 if ((l>y)||(x>r))return; 11 if ((x<=l)&&(r<=y)){ 12 f[k]=min(f[k],z); 13 return; 14 } 15 update(L,l,mid,x,y,z); 16 update(R,mid+1,r,x,y,z); 17 } 18 int query(int k,int l,int r,int x){ 19 if (l==r)return f[k]; 20 if (x<=mid)return min(query(L,l,mid,x),f[k]); 21 return min(query(R,mid+1,r,x),f[k]); 22 } 23 int copy(int kk){ 24 int k=++V; 25 mx[k]=mx[kk],ls[k]=ls[kk],rs[k]=rs[kk]; 26 return k; 27 } 28 void update(int &k,int l,int r,int x,int y){ 29 k=copy(k); 30 mx[k]=max(mx[k],y); 31 if (l==r)return; 32 if (x<=mid)update(ls[k],l,mid,x,y); 33 else update(rs[k],mid+1,r,x,y); 34 } 35 int find(int k,int l,int r,int x,int y){ 36 if ((!k)||(l>y)||(x>r))return 0; 37 if ((x<=l)&&(r<=y))return mx[k]; 38 return max(find(ls[k],l,mid,x,y),find(rs[k],mid+1,r,x,y)); 39 } 40 int main(){ 41 scanf("%d",&n); 42 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 43 for(int i=1;i<=n;i++)update(rt[i]=rt[i-1],0,1e9,a[i],i); 44 memset(f,0x3f,sizeof(f)); 45 scanf("%d",&m); 46 for(int i=1;i<=m;i++){ 47 scanf("%d%d",&x,&y); 48 v[y].push_back(make_pair(x,i)); 49 } 50 for(int i=1;i<=n;i++){ 51 x=find(rt[i-1],0,1e9,a[i],1e9); 52 while (x){ 53 update(1,1,n,1,x,a[x]-a[i]); 54 x=find(rt[x-1],0,1e9,a[i],(a[i]+a[x]-1)/2); 55 } 56 x=find(rt[i-1],0,1e9,0,a[i]); 57 while (x){ 58 update(1,1,n,1,x,a[i]-a[x]); 59 x=find(rt[x-1],0,1e9,(a[i]+a[x]+1)/2,a[i]); 60 } 61 for(int j=0;j<v[i].size();j++)ans[v[i][j].second]=query(1,1,n,v[i][j].first); 62 } 63 for(int i=1;i<=m;i++)printf("%d ",ans[i]); 64 }