做法: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; }