cfc++
luogu優化
沒有強制在線,因此能夠離線,把詢問按右端點排序,而後從左往右枚舉右端點,並維護左端點爲\(1\)到\(i\)的區間的答案,而後詢問就能夠直接取出來spa
如今優化這個過程.由於是兩個元素的最小絕對值,因此先考慮\(i>j,a_i\le a_j\)的貢獻,而後把序列和詢問端點顛倒過來再作一遍,就能考慮全部狀況.那麼這個過程能夠當作枚舉到右端點\(i\),而後找到最大的\(j<i\)知足\(a_i\le a_j\),更新左端點爲\(1\)到\(j\)的答案,而後繼續,找最大的\(j'<j\)知足\(a_i\le a_{j'}<a_j\),更新左端點爲\(1\)到\(j'\)的答案...可是仍是不優.進一步的,咱們加一個限制,咱們強制\(a_j-a_{j'}\le a_{j'}-a_i\),若是不知足這個條件,咱們就讓\((j',j)\)這個點對去更新答案,而且不會更劣.這樣子作,\(a_j\)和\(a_i\)之差每作一次至少減小一半,因此找\(j\)的過程用上可持久化線段樹,複雜度就是\(O(nlognlog_{\max a_i})\)code
注意每次更新的都是一段前綴,因此能夠把一個點答案改成後綴最小值,而後線段樹單點修改區間查詢便可排序
#include<bits/stdc++.h> #define LL long long #define uLL unsigned long long #define db double using namespace std; const int N=3e5+10; int rd() { int x=0,w=1;char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int n,m,q; int s[N*50],ch[N*50][2],rt[N],tt; void inst(int o1,int o2,int x,int y) { s[o1]=max(s[o2],y); int l=1,r=m; while(l<r) { int mid=(l+r)>>1; if(x<=mid) { ch[o1][0]=++tt,ch[o1][1]=ch[o2][1]; o1=ch[o1][0],o2=ch[o2][0]; r=mid; } else { ch[o1][0]=ch[o2][0],ch[o1][1]=++tt; o1=ch[o1][1],o2=ch[o2][1]; l=mid+1; } s[o1]=max(s[o2],y); } } int quer(int o,int l,int r,int ll,int rr) { if(!o||ll>rr) return 0; if(ll<=l&&r<=rr) return s[o]; int an=0,mid=(l+r)>>1; if(ll<=mid) an=max(an,quer(ch[o][0],l,mid,ll,rr)); if(rr>mid) an=max(an,quer(ch[o][1],mid+1,r,ll,rr)); return an; } int mi[N<<2]; void psup(int o){mi[o]=min(mi[o<<1],mi[o<<1|1]);} void modif(int o,int l,int r,int lx,int x) { if(l==r){mi[o]=min(mi[o],x);return;} int mid=(l+r)>>1; if(lx<=mid) modif(o<<1,l,mid,lx,x); else modif(o<<1|1,mid+1,r,lx,x); psup(o); } int q2(int o,int l,int r,int ll,int rr) { if(ll<=l&&r<=rr) return mi[o]; int an=1<<30,mid=(l+r)>>1; if(ll<=mid) an=min(an,q2(o<<1,l,mid,ll,rr)); if(rr>mid) an=min(an,q2(o<<1|1,mid+1,r,ll,rr)); return an; } int a[N],b[N],an[N]; struct QR { int l,r,i; bool operator < (const QR &bb) const {return r<bb.r;} }qq[N]; void wk() { while(tt) { s[tt]=ch[tt][0]=ch[tt][1]=0; --tt; } memset(mi,0x3f3f3f,sizeof(mi)); for(int i=1;i<=n;++i) inst(rt[i]=++tt,rt[i-1],a[i],i); for(int i=1,j=1;i<=n;++i) { int mx=1<<30,pp=i-1; while(1) { int rr=upper_bound(b+1,b+m+1,mx)-b-1,k=quer(rt[pp],1,m,a[i],rr); if(!k) break; pp=k-1; mx=b[a[k]]; modif(1,1,n,k,mx-b[a[i]]); if(mx==b[a[i]]) break; mx=(mx-b[a[i]]==1)?b[a[i]]:mx-(mx-b[a[i]])/2; } while(j<=q&&qq[j].r==i) { an[qq[j].i]=min(an[qq[j].i],q2(1,1,n,qq[j].l,qq[j].r)); ++j; } } } int main() { n=rd(); for(int i=1;i<=n;++i) a[i]=b[i]=rd(); sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1; b[++m]=1<<30|1; for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b; q=rd(); for(int i=1;i<=q;++i) { an[i]=1<<30; qq[i].l=rd(),qq[i].r=rd(),qq[i].i=i; } sort(qq+1,qq+q+1); wk(); reverse(a+1,a+n+1); for(int i=1;i<=q;++i) { qq[i].l=n-qq[i].l+1,qq[i].r=n-qq[i].r+1; swap(qq[i].l,qq[i].r); } sort(qq+1,qq+q+1); wk(); for(int i=1;i<=q;++i) printf("%d\n",an[i]); return 0; }