按照贪心策略,枚举以每个位置为结尾,则往前遍历,找到它的前一个数字最近的出现位置,然后往前跳n-1步,倍增判断一下
跳到了哪个点。然后线段树查询一下区间最大值即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
vector<int>G[maxn];
int n,m,Q,a[maxn],has[maxn];
int f[maxn][22],lg[maxn],vis[maxn];
int tree[maxn<<2],dep[maxn];
string s;
void update(int L,int C,int l,int r,int rt)
{
if(l==r)
{
tree[rt]=C;
return;
}
int mid=(l+r)/2;
if(L<=mid) update(L,C,l,mid,rt<<1);
else update(L,C,mid+1,r,rt<<1|1);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R) return tree[rt];
int ans=0,mid=(l+r)/2;
if(L<=mid) ans=max(ans,query(L,R,l,mid,rt<<1));
if(R>mid) ans=max(ans,query(L,R,mid+1,r,rt<<1|1));
return ans;
}
int cal(int v,int d)
{
if(d<1) return 0;
while(dep[v]>d)
{
int h=lg[dep[v]-d];
v=f[v][h];
}
return v;
}
int main()
{
for(int i=2;i<maxn;i++)
lg[i]=lg[i/2]+1;
scanf("%d%d%d",&n,&m,&Q);
for(int i=1,x;i<=n;i++)
{
scanf("%d",&x);
has[x]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d",&a[i]);
a[i]=has[a[i]];
if(a[i]==1) f[i][0]=vis[n],dep[i]=dep[vis[n]]+1;
else f[i][0]=vis[a[i]-1],dep[i]=dep[vis[a[i]-1]]+1;
for(int j=1;(1<<j)<=dep[i];j++)
f[i][j]=f[f[i][j-1]][j-1];
int v=cal(i,dep[i]-n+1);
update(i,v,1,m,1);
vis[a[i]]=i;
}
while(Q--)
{
int l,r;scanf("%d%d",&l,&r);
if(query(l,r,1,m,1)>=l) s+='1';
else s+='0';
}
cout<<s<<endl;
return 0;
}