1. 程式人生 > >最近等對 (unique、lower_bound、離散化的配合)

最近等對 (unique、lower_bound、離散化的配合)

一個 不變 解決 相等 去重 ace 個數 cmp efault

我的第一篇用了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≤100000
Output
對於每一個查詢,輸出最近的距離,如果沒有相等的元素,輸出-1。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sample Input

5 3

1 1 2 3 2

1 5

2 4

3 5

Sample Output

1

-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、離散化的配合)