做法:RMQ+二分
思路:
1.我们将相同的数作为一个区间存下来,将两个的坐标分别作为区间的左右端点。再把两个端点的差放在一个数组中,然后题目可以转化为数组区间找最小值。由此可以想到RMQst表
2.因为存的左右端点是有序的,在每次询问时,我们可以二分查找,找到可以得出答案的范围。
代码
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp(aa,bb) make_pair(aa,bb)
#define _for(i,b) for(int i=(0);i<(b);i++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,b,a) for(int i=(b);i>=(a);i--)
#define mst(abc,bca) memset(abc,bca,sizeof abc)
#define X first
#define Y second
#define lowbit(a) (a&(-a))
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long double ld;
const int N=5e5+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-6;
const double PI=acos(-1.0);
int n,m,cnt,f[N][20],logn[N];
unordered_map<int,int> mp;
int l[N],r[N];
void init(){
logn[1]=0;
logn[2]=1;
for(int i=3;i<=n;i++) {
logn[i]=logn[i>>1]+1;
}
}
void solve(){
cin>>n>>m;
init();
rep(i,1,n){
int a;cin>>a;
if(mp.count(a)){
int t=mp[a];
mp[a]=i;
if(cnt&&l[cnt]>=t) continue;
l[++cnt]=t,r[cnt]=i,f[cnt][0]=r[cnt]-l[cnt];
}
else mp[a]=i;
}
for(int j=1;j<=logn[cnt];j++){
for(int i=1;i<=cnt-(1<<j)+1;i++){
f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
while(m--){
int x,y,s;
cin>>x>>y;
x=lower_bound(l+1,l+cnt+1,x)-l;
y=upper_bound(r+1,r+cnt+1,y)-r-1;
if(x>y){
cout<<"-1\n";
continue;
}
s=logn[y-x+1];
cout<<min(f[x][s],f[y-(1<<s)+1][s])<<"\n";
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
#ifdef DEBUG
freopen("F:/laji/1.in", "r", stdin);
// freopen("F:/laji/2.out", "w", stdout);
#endif
// int t;cin>>t;while(t--)
solve();
return 0;
}
京公网安备 11010502036488号