一开始感觉用莫队可以搞一下,但是看了题解才发现这题其实是倍增套路题
把排列转换成nxt数组,然后倍增dp[i][j]表示第i个数后面有(1<<j)个数的最靠左的区间
然后从右往左扫一次即可
#include<bits/stdc++.h> using namespace std; #define maxn 200005 int dp[maxn][20],last[maxn],nxt[maxn],ans[maxn],a[maxn],b[maxn],n,m,t; //dp[i][j]表示第i个数开始的后面(1<<j)个数的位置 int main(){ cin>>n>>m>>t; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<=n;i++)nxt[a[i-1]]=a[i]; nxt[a[n]]=a[1]; for(int i=1;i<=m;i++)cin>>b[i]; for(int i=1;i<=n;i++)last[i]=m+1; for(int i=0;i<=19;i++)dp[m+1][i]=m+1; ans[m+1]=m+1; for(int i=m;i>=1;i--){ dp[i][0]=last[nxt[b[i]]]; last[b[i]]=i; for(int j=1;j<=19;j++)dp[i][j]=dp[dp[i][j-1]][j-1]; int cnt=n-1,pos=i; for(int j=19;j>=0;j--) if(cnt >= (1<<j)) cnt-=(1<<j),pos=dp[pos][j]; ans[i]=min(ans[i+1],pos); } for(int i=1;i<=t;i++){ int l,r; cin>>l>>r; if(ans[l]<=r)cout<<"1"; else cout<<"0"; } }