最近等對 (unique、lower_bound、離散化的配合)
我的第一篇用了unique、lower_bound、離散化的代碼!??ヽ(°▽°)ノ?
一篇寫的超好的離散化+unique函數+lower_bound函數等等函數的集合
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
題目:
現在有一個序列 a1, a2, ..., an ,還有m個查詢 lj, rj (1 ≤ lj ≤ rj ≤ n) 。對於每一個查詢,請找出距離最近的兩個元素 ax 和 ay (x ≠ y) ,並且滿足以下條件:
· lj ≤ x, y ≤ rj;
· ax = ay。
兩個數字的距離是他們下標之差的絕對值 |x − y| 。
Input單組測試數據。
第一行有兩個整數n, m ,表示序列的長度和查詢的次數。
第二行有n個整數a1,a2,...,an (-10^9≤ai≤10^9)。
接下來有m行,每一行給出兩個整數lj,rj (1≤lj≤rj≤n)表示一個查詢。
對於20%的數據,1≤n,m≤300
對於50%的數據,1≤n,m≤3000
對於100%的數據,1≤n,m≤100000Output
對於每一個查詢,輸出最近的距離,如果沒有相等的元素,輸出-1。Sample Input
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5 3
1 1 2 3 2
1 5
2 4
3 5
Sample Output1
-1
2
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
配有qiao詳細註釋的代碼:
#include<bits/stdc++.h> using namespace std; const int MAXN=500005,inf=90000000; int n,m,x,y,cnt,minn[MAXN<<2]; int next[MAXN],a[MAXN],s[MAXN],first[MAXN],ans[MAXN]; struct node{ int l,r,id; }q[MAXN]; //q[].id說明這是第id次詢問 bool cmp(node a,node b){ return a.r<b.r; } void build_tree(int l,int r,int o){ //一開始把整棵樹的最小值都設得很大 if (l==r){ minn[o]=inf; return; } int mid=l+r>>1; build_tree(l,mid,o<<1); build_tree(mid+1,r,o<<1|1); minn[o]=inf; } void change(int l,int r,int o,int x,int k){ //求每兩個等對之間的距離 if (l==r){ minn[o]=k; return; } int mid=l+r>>1; if (x<=mid) change(l,mid,o<<1,x,k); else change(mid+1,r,o<<1|1,x,k); minn[o]=min(minn[o<<1],minn[o<<1|1]); } int query(int l,int r,int o,int x,int y){ //詢問在這個區間的最小距離 if (x<=l&&r<=y) return minn[o]; int mid=l+r>>1; int ans=inf; if (x<=mid) ans=min(ans,query(l,mid,o<<1,x,y)); if (y>mid) ans=min(ans,query(mid+1,r,o<<1|1,x,y)); return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i]=a[i];//s[]是a[]的副本 for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); q[i].l=x,q[i].r=y,q[i].id=i; //q[i].id表示第i次查詢,把詢問信息記錄下來 } sort(s+1,s+n+1); //使用unique函數前要先排序,不然unique沒用 sort(q+1,q+m+1,cmp); //到時就可以從左到右找下去 cnt=unique(s+1,s+n+1)-s-1; //cnt表示s數組去重後元素的個數 for(int i=1;i<=n;i++) { //lower-bound返回的是把a[i]插進s數組中的位置(保持s的順序)(不會真插進去,只是返回它應在的位置) a[i]=lower_bound(s+1,s+cnt+1,a[i])-s; //a[]被離散化,成為新數組 ,元素順序不變 /*如:s[]:1 4 5 6 原a[]:1 5 4 6 4 1 5 現a[]:1 3 2 4 2 1 3 */ next[i]=first[a[i]],first[a[i]]=i; //first[a[i]]記錄值為a[i]的位置,next[i]為上一個a[i]的位置 }//這裏有點像鄰接表存圖 build_tree(1,n,1); for(int i=1,j=1;i<=n&&j<=m;i++){ if (next[i]!=0){ //next[i]!=0說明前面還有a[i]這個元素出現 change(1,n,1,next[i],i-next[i]);//i-next[i]代表它與上一個相同值的距離 } while (i==q[j].r&&j<=m){ ans[q[j].id]=query(1,n,1,q[j].l,q[j].r); j++; //query()完後這個詢問就解決完了,處理下一個 } } for(int i=1;i<=m;i++) { if(ans[i]<inf) printf("%d\n",ans[i]); else printf("-1\n"); //沒改過就說明不存在 } }
最近等對 (unique、lower_bound、離散化的配合)