这个题很多地方都想到了 最后卡在了倍增优化
显然一开始给了一个环 我们可以找出每个值的前驱 当我们遍历a数组的时候 我们需要找出最小的包含一个循环的区间 为啥是最小呢 假如 这个循环是 3 1 2 然后a数组是 3 3 1 2 显然对于r=4的时候 l=2是最小区间 对于l<2的情况我们都是认为满足条件的 而相反我们不能把l=1作为最小区间
所以对于每个r我们需要找出包含一个循环的最大的l (我们用ans数组来记录这个值)以此来判断询问是否ok
我们思考一下 当我们遍历到a数组的一个值时 我们可以根据pre数组向前走n-1步 最后走到的这个位置肯定是包含一个循环区间的(如果走到0说明不包含一个完整的循环 但是不影响询问)
但是我们肯定不能暴力的去走这n-1步 这样复杂度是n^2的
我们可以根据前驱记录父亲结点 然后用类似lca的方法(倍增法) 将n-1步进行二进制分解 从而在logn的时间内完成这个操作 不过根据第i个点走出来的l不一定是最大的l 所以我们要与ans[i-1]比较找出最大值 具体看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
const int N = 2e5+10;
const int inf = 1e9+1;
int p[N],a[N],pre[N],pos[N],ans[N],f[N][30],k[N];
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i = 1; i <= n; i++) scanf("%d",&p[i]);
for(int i = 1; i <= m; i++) scanf("%d",&a[i]);
for(int i = 2; i <= n; i++) pre[p[i]]=p[i-1];
pre[p[1]]=p[n];
int g = (int)(log(n)/log(2))+1;
k[0]=1;
for(int i = 1; i <= g; i++) k[i]=k[i-1]*2;
for(int i = 1; i <= m; i++){
f[i][0]=pos[pre[a[i]]];
for(int j = 1; j <= g; j++)//f数组初始化
f[i][j]=f[f[i][j-1]][j-1];
pos[a[i]]=i;
}
for(int i = 1; i <= m; i++){
int now = n-1,x = i;//now表示要走的步数 x表示当前结点
for(int j = g; j >= 0; j--){
if(now>=k[j]){//二进制拆分这个步数
now-=k[j];
x=f[x][j];
}
}
ans[i]=max(ans[i-1],x);//选择最大l
}
for(int i = 1; i <= q; i++){
int l,r;
scanf("%d%d",&l,&r);
if(ans[r]>=l) printf("1");//这就是为啥ans[r]=0也不影响 因为这样对所有的询问也是输出0
else printf("0");
}
puts("");
}