[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 }
View Code

 

posted @ 2021-07-14 17:45  PYWBKTDA  阅读(45)  评论(0编辑  收藏  举报