[cf765F]Souvenirs
离线,从小到大枚举右端点,维护左端点的答案,那么当右端点从$r-1$变为$r$时,即在原来的基础上考虑其中一个数为$a_{r}$的答案,并对原来的答案取$\min$
考虑另一个数为$a_{i}$,这里仅考虑$a_{r}\le a_{i}$的情况($a_{r}\ge a_{i}$类似):
此时,先找到最大的$1\le i_{1}<r$使得$a_{r}\le a_{i_{1}}$,不妨先对$[1,i_{1}]$的答案都用$a_{i_{1}}-a_{r}$去更新
接下来,注意到如果$a_{i_{2}}\ge \lceil\frac{a_{r}+a_{i_{1}}}{2}\rceil$则有$|a_{i_{1}}-a_{i_{2}}|\le a_{i_{2}}-a_{r}$,即其一定没有意义,那么只需要找到最大的$1\le i_{2}<i_{1}$使得$a_{r}\le a_{i_{2}}<\lceil\frac{a_{r}+a_{i_{1}}}{2}\rceil$即可
重复此过程,即不断找到最大的$1\le i_{t}<i_{t-1}$使得$a_{r}\le a_{i_{t}}<\lceil\frac{a_{r}+a_{i_{t-1}}}{2}\rceil$,由于$0\le a_{i_{t}}-a_{r}<\lceil\frac{a_{t-1}-a_{r}}{2}\rceil$,因此最多找$o(\log V)$次,每一次用线段树维护可以做到$o(\log V)$(其中$V$为值域)
关于线段树,可持久化常数过大,需要将权值离散并在线维护每种权值最后一次出现的位置
总复杂度即$o(n\log^{2}V+m\log 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 n,m,x,y,l,r,a[N],b[N],pos[N<<2],f[N],ans[N<<2]; 9 int lowbit(int k){ 10 return (k&(-k)); 11 } 12 void update(int k,int x){ 13 while (k){ 14 f[k]=min(f[k],x); 15 k^=lowbit(k); 16 } 17 } 18 int query(int k){ 19 int ans=f[0]; 20 while (k<=n){ 21 ans=min(ans,f[k]); 22 k+=lowbit(k); 23 } 24 return ans; 25 } 26 void update(int k,int l,int r,int x,int y){ 27 pos[k]=max(pos[k],y); 28 if (l==r)return; 29 if (x<=mid)update(L,l,mid,x,y); 30 else update(R,mid+1,r,x,y); 31 } 32 int query(int k,int l,int r,int x,int y){ 33 if ((l>y)||(x>r))return 0; 34 if ((x<=l)&&(r<=y))return pos[k]; 35 return max(query(L,l,mid,x,y),query(R,mid+1,r,x,y)); 36 } 37 int main(){ 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 40 scanf("%d",&m); 41 for(int i=1;i<=m;i++){ 42 scanf("%d%d",&x,&y); 43 v[y].push_back(make_pair(x,i)); 44 } 45 memcpy(b,a,sizeof(a)); 46 memset(f,0x3f,sizeof(f)); 47 sort(b+1,b+n+1); 48 for(int i=1;i<=n;i++){ 49 int pos=lower_bound(b+1,b+n+1,a[i])-b; 50 l=pos,r=n; 51 while (1){ 52 int Pos=query(1,1,n,l,r); 53 if (!Pos)break; 54 update(Pos,a[Pos]-a[i]); 55 r=upper_bound(b+1,b+n+1,(a[i]+a[Pos]-1>>1))-b-1; 56 } 57 l=1,r=pos; 58 while (1){ 59 int Pos=query(1,1,n,l,r); 60 if (!Pos)break; 61 update(Pos,a[i]-a[Pos]); 62 l=upper_bound(b+1,b+n+1,(a[i]+a[Pos]>>1))-b; 63 } 64 update(1,1,n,pos,i); 65 for(int j=0;j<v[i].size();j++)ans[v[i][j].second]=query(v[i][j].first); 66 } 67 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 68 return 0; 69 }