- 開始讀錯題了,覺得是連續的一段,敲完後才發現是 \(subsequence\) ...
- 考慮對於 \(a\) 中的每一個 \(a_i\) 找到它在排列 \(p\) 中的下一個元素的最左位置 \(j\) ,從 \(i\) 到 \(j\) 連一條邊,這樣就造成了一個森林.
- 而後 \(dfs\) 遍歷一下,用一個棧來存儲當前在路徑中的點,若當前節點爲 \(u\) ,而路徑長 \(\geq n\) ,說明路徑中從 \(u\) 開始的 \(n\) 個位置構成了一個 \(cyclic\ shift\) .
- 這樣就能夠處理出以點 \(i\) 爲第一個元素,能找到的 \(cyclic\ shift\) 最後一個元素的最左位置 \(minr_i\).對這個東西取一下後綴 \(\min\) ,則它表示後綴 \(i\sim n\) 中能找到的 \(cyclic\ shift\) 最後一個元素的最左位置 .
- 對於每一個詢問 \((l,r)\) ,只需判斷是否有 \(r \leq minr_l\) 便可.
- 時間複雜度 \(O(n+Q)\).
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define mp make_pair
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=2e5+10;
int n,m,Q;
int a[MAXN],b[MAXN],nxp[MAXN];
int pos[MAXN];
queue<char> buf;
int cnt=0,head[MAXN],to[MAXN],nx[MAXN];
inline void addedge(int u,int v)
{
++cnt;
to[cnt]=v;
nx[cnt]=head[u];
head[u]=cnt;
}
int vis[MAXN];
int minr[MAXN];
int stk[MAXN],tp=0;
void dfs(int u)
{
vis[u]=1;
stk[++tp]=u;
if(tp>=n)
minr[u]=min(minr[u],stk[tp-n+1]);
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(!vis[v])
dfs(v);
}
--tp;
}
int main()
{
n=read(),m=read(),Q=read();
for(int i=1;i<=n;++i)
a[i]=read();
for(int i=1;i<=m;++i)
b[i]=read();
a[0]=a[n],a[n+1]=a[1];
for(int i=1;i<=n;++i)
nxp[a[i]]=a[i+1];
for(int i=m;i>=1;--i)
{
pos[b[i]]=i;
int pre=nxp[b[i]];
if(pos[pre])
addedge(pos[pre],i);
}
memset(minr,0x7f,sizeof minr);
for(int i=m;i>=1;--i)
{
if(!vis[i])
dfs(i);
minr[i]=min(minr[i],minr[i+1]);
}
while(Q--)
{
int l=read(),r=read();
if(minr[l]<=r)
buf.push('1');
else
buf.push('0');
}
while(!buf.empty())
{
putchar(buf.front());
buf.pop();
}
return 0;
}