atcoder.jp/contests/ab…
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
const int inf=1e9;
int a[N],b[N],n;
int val[N];
int l[N],r[N];
int pos[N];
int pre[N],suf[N];
bool chk[N];
bool vis[N];
//判断:A的前x个,在b的y中必须出现
//b的前y个不能出现a中没有的数
//pos[i]记录i在b中第一次出现的位置
//chk[i]//标记i在a中是否第一次出现
//pre[x]a的前x个数在b中最晚的出现位置
//suf[x]a的后x个数在b中出现的最早位置
//mn b中出现最早,在a中没有的数的位置
//对每个x,合法的区间在l[x],r[x]
signed main(){
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++){cin>>a[i];val[++cnt]=a[i];
}for(int i=1;i<=n;i++){cin>>b[i];val[++cnt]=b[i];
}sort(val+1,val+cnt+1);
int len=unique(val+1,val+cnt+1)-val-1;
//映射成1-len
for(int i=1;i<=n;i++)a[i]=lower_bound(val+1,val+len+1,a[i])-val;
for(int i=1;i<=n;i++)b[i]=lower_bound(val+1,val+len+1,b[i])-val;
for(int i=1;i<=n;i++)if(!pos[b[i]])pos[b[i]]=i;//记录v在b中出现的第一个位置
for(int i=1;i<=n;i++)if(!vis[a[i]]){
vis[a[i]]=i;chk[i]=1;}
pre[0]=0;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1];;
if(chk[i])pre[i]=max(pre[i],pos[a[i]]==0?n+1:pos[a[i]]);
}
suf[n+1]=n+1;
for(int i=n;i>=1;i--){
suf[i]=suf[i+1];//后面所有数出现的最早位置
//不能包含后面的数
if(chk[i])suf[i]=min(suf[i],pos[a[i]]==0?n+1:pos[a[i]]);
}
//在b中出现,在a中未出现的最早位置
int mn=n+1;
for(int i=1;i<=n;i++)if(!vis[b[i]])mn=min(mn,i);
//对每个x,算[l[x],r[x]]
for(int i=1;i<=n;i++){
if(!chk[i]){l[i]=l[i-1],r[i]=r[i-1];continue;}//之前的
l[i]=pre[i]; // y必须 >= 所有A前x中新数在B中的首次出现位置
r[i]=min(suf[i+1],mn)-1; // y必须 < 最早出现A没有的数的位置
}
int q;
cin>>q;
while(q--){
int x;int y;cin>>x>>y;
// 如果y落在 [l[x], r[x]] 里,输出Yes
puts(l[x]<=y&&y<=r[x]?"Yes":"No");
}
}
思路
本题使用后缀最小值 suf 来确定查询的合法上限,确保 B 的前 y 项不会出现 A 前 x 项中不存在的数字,从而保证集合完全相等。前缀负责下限,后缀负责上限,二者共同构成合法查询区间,实现离线 O (1) 查询。