E. Lynyrd Skynyrd
题意:
输入
n
,
m
,
q
(
2
e
5
)
n,m,q(2e5)
n,m,q(2e5)
接下来输入
p
1
,
p
2
,
…
,
p
n
p_1,p_2,\dots,p_n
p1,p2,…,pn,表示一个
n
n
n的排列;
接下来输入
a
1
,
a
2
,
…
,
a
m
a_1,a_2,\dots,a_m
a1,a2,…,am,
接下来
q
q
q行,表示
q
q
q个询问;
每个询问输入
l
,
r
(
1
≤
l
≤
r
≤
m
)
l,r(1\leq l\leq r\leq m)
l,r(1≤l≤r≤m),问是否数组
a
,
l
−
r
a,l-r
a,l−r内,会有
p
p
p排列的一个循环块(如
p
p
p为
1
,
3
,
2
1,3,2
1,3,2,那么
1
,
3
,
2
1,3,2
1,3,2;
3
,
2
,
1
3,2,1
3,2,1;
2
,
1
,
3
2,1,3
2,1,3都是)。
题解:
这题其实挺简单的,用倍增就好。
即对于一个点R,找到最大的L,使L跳到R可以形成一个循环块,如何实现,用倍增,对于每一个R,它的上一个点的位置必能很容易的就可以找到,然后倍增一下,最后再来跳的找L;找到之后注意于R-1对应的L比较大小。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+9;
int n,m,q;
int p[N],a[N],pre[N],pos[N],f[N][29],l[N];
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m>>q;
for(int i=0;i<n;i++)cin>>p[i];
for(int i=0;i<n;i++)pre[p[i]]=p[(i-1+n)%n];
for(int i=1;i<=m;i++){
cin>>a[i];f[i][0]=pos[pre[a[i]]];pos[a[i]]=i;
// cout<<pre[a[i]]<<" "<<f[i][0]<<endl;
for(int j=1;j<=20;j++)f[i][j]=f[f[i][j-1]][j-1];
int t=n-1;l[i]=i;
for(int j=20;j>=0;j--)if(t&(1<<j))l[i]=f[l[i]][j];
l[i]=max(l[i],l[i-1]);//这步很关键,漏了过不了。
// cout<<l[i]<<" ";
}
// cout<<endl;
for(int i=1,u,v;i<=q;i++){
cin>>u>>v;
if(l[v]>=u)cout<<1;else cout<<0;
}
cout<<endl;
return 0;
}