題意:給你一個長度爲n的序列{ai},有m個詢問,每次詢問給出l,r,問在全部$l\le x < y\le r$中,$|a_x-a_y|$的最小值是多少。node
$n\le 10^5,m\le 3\times 10^5,a_i\le 10^9$ios
題解:網上的標程都是在線段樹上搞一搞就完事了,可是我怎麼看都以爲是$O(n\log^3n)$的。看官方題解,裏面也沒寫具體作法。因而我一臉懵逼的狀況下用了主席樹來維護,起碼保證了$O(n\log^2n)$的複雜度。(應該是作麻煩了)數組
說作法吧。咱們先只考慮$j<i,a_j>a_i$的狀況,而後反過來再作一遍。首先比較暴力的思路就是先將詢問離線,按右端點排序,而後枚舉右端點。當咱們掃到一個右端點i的時候,先找到i左邊第一個比它大的數j,用$a_j-a_i$更新j左邊的答案,而後不斷找到j左邊,比$a_j$小,比$a_i$大的j',重複此步驟作下去。spa
而一個比較重要的性質就是咱們找到的j'只有在知足$a_{j'}-a_i<a_j-a_{j'}$的狀況下才是有意義的(不然就用$a_j-a_{j'}$作答案了),因此每次咱們的差都會減半,所需次數爲log次。若是用樹狀數組更新答案的話複雜度就是$O(n\log n\log a_i)$的了。blog
可是怎麼找到下一個$j'$呢?我比較菜因此用的主席樹。排序
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> using namespace std; int n,m,N,top,pre,tot; const int maxn=100010; int v[maxn],st[maxn],sn[maxn],ans[maxn*3],p[maxn],rk[maxn],ref[maxn],rt[maxn]; struct node { int x,org; node() {} node(int a,int b) {x=a,org=b;} }; vector<node> q[maxn]; vector<node>::iterator it; int val[maxn<<2]; struct sag { int ls,rs,siz; }s[maxn*20]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } bool cmp(const int &a,const int &b) {return v[a]<v[b];} inline void updata(int x,int val) { for(int i=x;i;i-=i&-i) sn[i]=min(sn[i],val); } inline int query(int x) { int ret=1<<30; for(int i=x;i<=n;i+=i&-i) ret=min(ret,sn[i]); return ret; } inline void insert(int x,int &y,int l,int r,int a) { y=++tot,s[y].ls=s[x].ls,s[y].rs=s[x].rs,s[y].siz=s[x].siz+1; if(l==r) return ; int mid=(l+r)>>1; if(a<=mid) insert(s[x].ls,s[y].ls,l,mid,a); else insert(s[x].rs,s[y].rs,mid+1,r,a); } inline int getrank(int x,int y,int l,int r,int a) { if(l==r) return s[y].siz-s[x].siz; int mid=(l+r)>>1; if(a<=mid) return getrank(s[x].ls,s[y].ls,l,mid,a); return s[s[y].ls].siz-s[s[x].ls].siz+getrank(s[x].rs,s[y].rs,mid+1,r,a); } inline int find(int x,int y,int l,int r,int a) { if(l==r) return l; int mid=(l+r)>>1,t=s[s[y].ls].siz-s[s[x].ls].siz; if(a<=t) return find(s[x].ls,s[y].ls,l,mid,a); return find(s[x].rs,s[y].rs,mid+1,r,a-t); } void work() { int i,j,t,last; for(i=1;i<=n;i++) p[i]=i; sort(p+1,p+n+1,cmp); for(N=0,i=1;i<=n;i++) { if(i==1||v[p[i]]>v[p[i-1]]) ref[++N]=v[p[i]]; rk[p[i]]=N; } ref[0]=-1<<30,ref[N+1]=1<<30; tot=0; for(i=1;i<=n;i++) insert(rt[rk[p[i-1]]],rt[rk[p[i]]],1,n,p[i]); memset(sn,0x3f,sizeof(sn)); for(st[top=0]=0,i=1;i<=n;i++) { while(top&&rk[st[top]]<rk[i]) top--; last=st[top]; while(last) { updata(last,v[last]-v[i]); if(rk[last]==rk[i]) break; pre=0; j=upper_bound(ref+1,ref+N+1,(v[last]+v[i])>>1)-ref-1; if(ref[j]<v[i]) break; t=getrank(rt[rk[i]-1],rt[j],1,n,i); if(t==1) break; last=find(rt[rk[i]-1],rt[j],1,n,t-1); } for(it=q[i].begin();it!=q[i].end();it++) ans[(*it).org]=min(ans[(*it).org],query((*it).x)); st[++top]=i; } } int main() { n=rd(); int i,a,b; for(i=1;i<=n;i++) v[i]=rd(); m=rd(); memset(ans,0x3f,sizeof(ans)); for(i=1;i<=m;i++) a=rd(),b=rd(),q[b].push_back(node(a,i)); work(); for(i=1;i<=n;i++) v[i]=-v[i]; work(); for(i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }//3 1 1 1 1 1 2