[cf765F]Souvenirs

离线,从小到大枚举右端点,维护左端点的答案,那么当右端点从$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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/15012130.html