cf1143E 倍增好题!

一开始感觉用莫队可以搞一下,但是看了题解才发现这题其实是倍增套路题

把排列转换成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";
    }
}
原文地址:https://www.cnblogs.com/zsben991126/p/10638911.html