题目链接:http://codeforces.com/contest/765/problem/F
题意概述:
给出一个序列,若干组询问,问给出下标区间中两数作差的最小绝对值。
分析:
这个题揭示着数据结构题目世界的真谛......
在线显然凉凉......考虑离线做法。
本题的主要思想:
首先考虑把所有的询问按照右端点排序,用一个指针扫整个序列,同时考虑i作为一组差的右端可以对右端点大于等于i的询问做出的贡献。我们可以发现,我们扫到当前点i,对于所有询问的右端点大于等于i的询问,如果其左端点小于等于i,那么i这个位置就可能对它们的答案做出贡献,换句话说我们只要考虑i作为差的右端可以对哪些左端的答案做出贡献,然后维护当前每个点作为左端的答案,查询的时候直接进行区间最小值的查询即可。
绝对值是麻烦的,因此我们简单一点,考虑所有j<i并且aj>=ai的贡献,然后倒着扫一遍就可以考虑剩下的可能贡献。
假设我们现在扫到位置i,左边有第一个大于ai的元素aj,我们贪心考虑,最终能够让 i作为下标较大的一方参与的答案变得更小 的j'满足:ai<=aj'<aj。但是这个性质显然还不够强,我们继续考虑,发现:
当aj'-ai>aj-aj'时,我们反向扫回来的时候,由于区间[j',j]一定被[j',i]包含,如果存在一个询问包括了[j',i],那么也一定包括了[j',j],显然这个时候aj-aj'是一个更加优秀的答案,aj'-ai更劣。
因此我们找到的j'一定要满足:aj'-ai<=aj-aj' -> 2aj'<=ai+aj,也就是说我们最多找到O(log(ai+a_first_j))个可以对i作为右端点的答案产生贡献的位置。
因为我们将右端点排序,因此我们维护当前所有的点作为下标较小的一方参与的时候的答案,当我们遇到一个询问p的右端点pr=i的时候,只需要查询区间[pl,i]中的最小值即可。
最后倒着来一遍,得到最终的答案。
在log次查找的时候我们实质上找的是权值在[ai,(ai+aj)/2]范围中的小于j的最大下标,分析一下发现可以直接用一棵权值线段树维护,因为我们找的权值区间内的序列下标不可能大于j(不然的话我们在之前就应该找到它了)。
找到第一个j的时候可以直接在序列线段树中进行二分。
时间复杂度O(NlogNloga)
(PS:突然发现变量rank,hash在C++11下面编译不了是什么情况?!)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 #define inf (1e9+5) 13 using namespace std; 14 const int MAXN=100005; 15 const int MAXM=300005; 16 17 int N,M,A[MAXN],Rank[MAXN],B[MAXN],ans[MAXM],tot; 18 struct data{ 19 int l,r,id; 20 friend bool operator < (data x,data y){ 21 return x.r<y.r; 22 } 23 }q[MAXM]; 24 struct segment_tree{ 25 static const int maxn=200005; 26 int rt,np,lc[maxn],rc[maxn],mx[maxn],mn[maxn]; 27 void init(){ rt=np=0; } 28 void pushup1(int now){ mn[now]=min(mn[lc[now]],mn[rc[now]]); } 29 void pushup2(int now){ mx[now]=max(mx[lc[now]],mx[rc[now]]); } 30 void build(int &now,int L,int R){ 31 now=++np,lc[now]=rc[now]=0,mx[now]=-1,mn[now]=inf; 32 if(L==R) return; 33 int m=L+R>>1; 34 build(lc[now],L,m); 35 build(rc[now],m+1,R); 36 } 37 void update1(int now,int L,int R,int pos,int v){ 38 if(L==R){ mn[now]=min(mn[now],v); return; } 39 int m=L+R>>1; 40 if(pos<=m) update1(lc[now],L,m,pos,v); 41 else update1(rc[now],m+1,R,pos,v); 42 pushup1(now); 43 } 44 void update2(int now,int L,int R,int pos,int v){ 45 if(L==R){ mx[now]=max(mx[now],v); return; } 46 int m=L+R>>1; 47 if(pos<=m) update2(lc[now],L,m,pos,v); 48 else update2(rc[now],m+1,R,pos,v); 49 pushup2(now); 50 } 51 int query_p(int now,int L,int R,int v){ 52 if(L==R) return mx[now]>=v?L:-1; 53 int m=L+R>>1; 54 if(mx[rc[now]]>=v) return query_p(rc[now],m+1,R,v); 55 return query_p(lc[now],L,m,v); 56 } 57 int query_max(int now,int L,int R,int A,int B){ 58 if(A<=L&&R<=B) return mx[now]; 59 int m=L+R>>1; 60 if(B<=m) return query_max(lc[now],L,m,A,B); 61 if(A>m) return query_max(rc[now],m+1,R,A,B); 62 return max(query_max(lc[now],L,m,A,B),query_max(rc[now],m+1,R,A,B)); 63 } 64 int query_min(int now,int L,int R,int A,int B){ 65 if(A<=L&&R<=B) return mn[now]; 66 int m=L+R>>1; 67 if(B<=m) return query_min(lc[now],L,m,A,B); 68 if(A>m) return query_min(rc[now],m+1,R,A,B); 69 return min(query_min(lc[now],L,m,A,B),query_min(rc[now],m+1,R,A,B)); 70 } 71 }st1,st2; 72 73 void data_in() 74 { 75 scanf("%d",&N); 76 for(int i=1;i<=N;i++) scanf("%d",&A[i]); 77 scanf("%d",&M); 78 for(int i=1;i<=M;i++){ 79 scanf("%d%d",&q[i].l,&q[i].r); 80 q[i].id=i; 81 } 82 } 83 int id(int v){ return upper_bound(B+1,B+tot+1,v)-B-1; } 84 void solve() 85 { 86 st1.init(); st2.init(); 87 st1.build(st1.rt,1,N); st2.build(st2.rt,1,tot); 88 int p=1; 89 st1.update2(st1.rt,1,N,1,A[1]); 90 st2.update2(st2.rt,1,tot,Rank[1],1); 91 for(int i=2;i<=N;i++){ 92 int j=st1.query_p(st1.rt,1,N,A[i]); 93 if(j!=-1){ 94 st1.update1(st1.rt,1,N,j,A[j]-A[i]); 95 while((j=st2.query_max(st2.rt,1,tot,Rank[i],id((A[i]+A[j])/2)))!=-1){ 96 st1.update1(st1.rt,1,N,j,A[j]-A[i]); 97 if(A[j]-A[i]==0) break; 98 } 99 } 100 while(p<=M&&q[p].r<=i){ 101 ans[q[p].id]=min(ans[q[p].id],st1.query_min(st1.rt,1,N,q[p].l,q[p].r)); 102 p++; 103 } 104 if(p>M) break; 105 st1.update2(st1.rt,1,N,i,A[i]); 106 st2.update2(st2.rt,1,tot,Rank[i],i); 107 } 108 } 109 void work() 110 { 111 memcpy(B,A,sizeof(A)); 112 sort(B+1,B+N+1); 113 tot=unique(B+1,B+N+1)-B-1; 114 115 for(int i=1;i<=N;i++) Rank[i]=lower_bound(B+1,B+tot+1,A[i])-B; 116 for(int i=1;i<=M;i++) ans[i]=inf; 117 sort(q+1,q+M+1); 118 solve(); 119 120 int l=1,r=N; 121 while(l<r) swap(Rank[l],Rank[r]),swap(A[l++],A[r--]); 122 for(int i=1;i<=M;i++){ 123 swap(q[i].l,q[i].r); 124 q[i].l=N-q[i].l+1,q[i].r=N-q[i].r+1; 125 } 126 sort(q+1,q+M+1); 127 solve(); 128 129 for(int i=1;i<=M;i++) printf("%d ",ans); 130 } 131 int main() 132 { 133 data_in(); 134 work(); 135 return 0; 136 }