最近等对 (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

时间: 2024-11-03 14:43:19

最近等对 (unique、lower_bound、离散化的配合)的相关文章

unique &amp; lower_bound C++

原来C++也有unique和lower_bound,只需头文件iostream unique unique可以对数组进行相邻元素的"去重",实现效果是把所有不重复的元素按顺序放在数组前面,剩余元素留在末尾.函数返回的是指针,表示最后一个唯一元素的位置的下一个地址值 假设a为大小为n的数组,且已经排好序,那么m=unique(a,a+n)-a,则m就是a中unique元素的个数,且a[:m]是已经去重后的数组,看一下例子就明白了: int a[7] = {1,1,2,2,3,4,6};

hdu 4400 Mines(离散化+bfs+枚举)

Problem Description Terrorists put some mines in a crowded square recently. The police evacuate all people in time before any mine explodes. Now the police want all the mines be ignited. The police will take many operations to do the job. In each ope

bzoj1935 [Shoi2007]园丁的烦恼

bzoj1935 [Shoi2007]园丁的烦恼 有N个点坐标为(xi,yi),M次询问,询问(a,b)-(c,d)的矩形内有多少点. 0≤n≤500000,1≤m≤500000,0≤xi,yi≤10000000 看完数据范围傻眼系列. 做法: 离线处理 因为这个范围肯定不能把x y都离散, 所以只把点和询问的y坐标放在一起都离散化,然后一起按x坐标排序, 再开一个树状数组,求出每个需要的点的二维前缀和. 不理解的话拿画图板画一下就好了. 细节见代码 #include<bits/stdc++.h

最长k可重区间集问题

最长k可重区间集问题 题目链接 https://www.luogu.org/problemnew/show/3358 做法 所有点向下一个点连容量为k费用为0的边 l和r连容量为1费用为区间长度的边 然后跑最大流最大费用流 (最大费用就是把边权取相反数跑最小费用 最后再输出最终费用的相反数) 思考 在整张图中,只有l - >r的边有费用 而且费用为区间长度 (i->i+1费用为0) 所以跑最大费用也就是求最长区间 #include <algorithm> #include <

luoguP1955 程序自动分析

P1955 程序自动分析 2017-09-12 题目描述 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3...代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足.例如,一个问题中的约束条件为:x1=x2,x2=x3,x3=x4,x4≠x1,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足. 现

[模板总结] Java的一些模板

快速排序(数组a从小到大,参数1是待排序的数组,参数2是起始下标,参数3是终止下标): 1 static void sort(int [] a, int l,int r){ 2 int m = l+r>>1; 3 int i=l, j = r; 4 do{ 5 while( a[i]<a[m] ) i++; 6 while( a[j]>a[m] ) j--; 7 if( i<=j ){ 8 int t = a[i]; 9 a[i] = a[j]; 10 a[j] = t; 1

数据离散化 ( 以及 stl 中的 unique( ) 的用法 )+ bzoj3289:Mato的文件管理

http://blog.csdn.net/gokou_ruri/article/details/7723378 ↑惯例Mark大神的博客 bzoj3289:Mato的文件管理 线段树求逆序对+莫队,但是数据量50000却没有给出范围,既然求逆序对,那么我们关注的只是数据之间的相对大小,此时我们可以把这50000个数据进行简化...嗯看大神的博客就明白了不需要多解释什么了..   下面是博客中未授权截取的大神的代码板子....不过都是自己看应该也没什么吧..... sort(sub_a,sub_a

Maximum Value(unique函数,lower_bound()函数,upper_bound()函数的使用)

传送门 在看大佬的代码时候遇到了unique函数以及二分查找的lower_bound和upper_bound函数,所以写这篇文章来记录以备复习. unique函数 在STL中unique函数是一个去重函数, unique的功能是去除相邻的重复元素(只保留一个),其实它并不真正把重复的元素删除,是把重复的元素移到后面去了,然后依然保存到了原数组中,然后 返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序. STL中关于二分查找的函数有三个lower_

离散化模板

关于离散化, 推荐几篇博客 http://www.matrix67.com/blog/archives/108 http://blog.csdn.net/doyouseeman/article/details/51154142 #include<cstdio> #include<algorithm> using namespace std; int a[10001],date[10001],n; int main() { scanf("%d",&n);