我的第一篇用了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