最近等对 (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≤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");                //没改过就说明不存在 
    }
} 

 

转载于:https://www.cnblogs.com/lxy050129/p/10538247.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值