这种区间找最近点我首先考虑使用单调栈/单调队列,因为ai与bi在不同的位置,想了一下感觉行不通,可以用st表存储ai的最大值,通过二分查找找到第一个大于所求的点下标,因为是一个环,我将数组复制三份(后面想想感觉原数组前面存储数组的后半部分,原数组后面再多存储数组的前半部分就行了吧),通过找到左边第一个和右边第一个符合条件的点,再比较一下,就可以得出该点的答案.
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[300005],b[300005],ans[100005];
int f[300005][20];
void init(int a[],int n){
for(int i=1;i<=n;i++)f[i][0]=a[i];
for(int j=1;1<<j<=n;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l,int r){
int k=log2(r-l+1);
// cout<<kw<<endl;
return max(f[l][k],f[r+1-(1<<k)][k]);
}
int solve(int l,int r,int value){
if(l==r){
if(a[l]>=value)return l;
}
else{
int mid=l+(r-l)/2;
if(query(l,mid)>=value)return solve(l,mid,value);
else return solve(mid+1,r,value);
}
return 0;
}
int solve2(int l,int r,int value){
if(l==r){
if(a[l]>=value)return l;
}
else{
int mid=l+(r-l)/2;
if(query(mid+1,r)>=value)return solve2(mid+1,r,value);
else return solve2(l,mid,value);
}
return 0;
}
signed main(){
int n;
scanf("%lld",&n);
for(int i=n+1;i<=2*n;i++){
scanf("%lld",&a[i]);
a[n+i]=a[i];
a[i-n]=a[i];
}
for(int i=n+1;i<=2*n;i++){
scanf("%lld",&b[i]);
b[n+i]=b[i];
b[i-n]=b[i];
}
init(a,3*n);
// cout<<query(2,3)<<endl;
int x,y;
for(int i=n+1;i<=2*n;i++){
if(query(i+1,n+i-1)<b[i]){
printf("-1 ");
}
else{
x=solve(i+1,n+i-1,b[i]);
y=solve2(i-n+1,i-1,b[i]);
printf("%lld ",min(x-i,i-y));
}
}
return 0;
}